poj 2686 状压DP

本文介绍了一种使用状态压缩动态规划(状压DP)解决旅行问题的方法,通过将问题转化为有向无环图(DAG)进行求解,有效地减少了状态空间,实现了对最优路径的快速查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//    挑战上的状压例题,感觉思路挺清晰,但是很难想...
//    不过学到了一个套路,那就是转换成DAG进行DP,很妙
//    车票状态为第一维度,顶点为第二维度。
//    DP[S][u]表示在u点时,车票状态集合为S的最小花费。
//    则状态转移为在u点找一张车票i,找一个点v.
//    DP[S \ i][v] = min(DP[S][u] + dist[u][v] / T[i]);

//    起始状态DP[所有车票][a] = 0;其他为无穷大。
//    结果为 min(dp[车票][b]); 因此集合应该从大到小枚举 

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 10;
const int maxm = 40;
const int INF = 0x7fffffff;
int mp[maxm][maxm];
int n,m,a,b,p;
int T[maxn];

double dp[1 << maxn][maxm];

void DP(){
    for (int i = 0;i < (1 << n);i ++)
        fill(dp[i],dp[i] + m,INF);

    dp[(1 << n) - 1][a - 1] = 0;

    for (int S = (1 << n) - 1; S >= 0; S --){

        for (int u = 0; u < m;u ++){
            for (int i = 0;i < n;i ++){
                if ((S >> i) & 1){

                    for (int v = 0; v < m; v++){
                        if (mp[v][u] > 0){
                            dp[S & ~(1 << i)][u] = min(dp[S & ~(1 << i)][u],
                                           dp[S][v] + mp[v][u] *1.0 / T[i]);
                        }
                    }
                }
            }
        }
    }

    double res = INF;

    for (int i = 0;i < 1 << n;i ++)
            res = min(res,dp[i][b - 1]);

    if (res < INF){
        printf("%.3lf\n",res);
    }else {
        puts("Impossible");
    }

}

int main(){
    //freopen("1.txt","r",stdin);
  while(scanf("%d%d%d%d%d",&n,&m,&p,&a,&b)!=EOF){
    if (n == 0 && m == 0)
        break;

    for (int i = 0;i < n;i ++)
        scanf("%d",&T[i]);
    memset(mp,0,sizeof(mp));
    for (int i = 0;i < p;i ++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        mp[x - 1][y - 1] = mp[y - 1][x - 1] = z;
    }

    DP();
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值