POJ - 2686 Traveling by Stagecoach (状压dp)
题意
有一个旅行家计划乘马车旅行,他所在的国家里共有m个城市,在城市之间有若干道路相连,从某个城市沿着某条道路到相邻城市需要乘坐马车。而乘坐马车需要使用车票,每用一张车票只可以通过一条道路。每张车票上都记有马的匹数,从一个城市移动到另一个城市的所需时间等于城市之间的道路的长度除以马的数量的结果。这位旅行家一共有n张车票,第i张车票上的马的匹数是ti,一张车票只能使用一次,并且换乘所需要的时间可以忽略。求从城市a到城市b所需要的最短时间。如果无法到达城市b就输出“Impossible”
思路
dp[s][u]表示现在在城市u,此时剩下的车票的集合为s。从当前状态出发,使用一张车票i∈s移动到相邻城市v,就相当于转移到了“在城市v,此时还剩下的车票的集合为s{i}”这个状态,把这个状态转移看成一条边,边上花费就是(u-v的道路长度)/ti。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 30;
int n, m, p, a, b;
int t[MAXN];
const double inf = 10000000;
double dp[1 << 13][MAXN];
double d[MAXN][MAXN];
int mmm;
int main() {
while (scanf("%d%d%d%d%d", &n, &m, &p, &a, &b) != EOF) {
if(!m && !n && !p && !a && !b) break;
a--,b--;
memset(d, -1, sizeof(d));
memset(t, 0, sizeof(t));
for(int i = 0; i < n; i++) scanf("%d", &t[i]);
int u, v;
double dis;
for(int i = 0; i < p; i++) {
scanf("%d%d%lf", &u, &v, &dis);
u--,v--;
d[u][v] = dis;
d[v][u] = dis;
}
for(int i = 0; i < (1<<12)-1; i++) {
for(int j = 0; j <= MAXN; j++) {
dp[i][j] = inf;
}
}
dp[(1<<n)-1][b] = 0;
double res = inf;
for(int s = (1<<n)-1; s>=0; s--) {
for(int i = 0; i<n; i++) {
if(s>>i&1) {
for(int u =0; u<m; u++) {
for(int v=0; v<m; v++) {
if(d[u][v]>=0) {
dp[s][v] = min(dp[s][v], dp[s&~(1<<i)][u] + (double)d[u][v] / (double)t[i]);
}
}
}
}
}
res = min(res,dp[s][b]);
}
if(res >= inf)printf("Impossible\n");
else printf("%.3f\n", res);
}
return 0;
}