POJ2686 状态压缩dp

题目大意:

n张票,m个城市,p条路,a是出发地,b是目的地,然后n张票上面都会有马的数目。从a走到b中,经过每条路都需要时间,并且一定要借助马。时间 = 路程/马的数量。问,如何走才能让时间最短(每张票只能使用一次)。


挑战程序竞赛上的例题P193.

代码我就弱弱的贴一下吧

#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; //n是票的数目,m是城市的数目,p道路的数目,a是出发城市,b是目标城市 const int inf = 0x3f3f3f3f; const int maxn = 8; const int maxm = 30; int n, m, p, a, b; int edge[maxm][maxm]; int t[maxn]; double dp[1 << maxn][maxm]; void solve(){ for (int i = 0; i < (1 << n); i++){ fill(dp[i], dp[i] + m, inf); } dp[(1 << n) - 1][a - 1] = 0; double res = inf; for (int s = (1 << n) - 1; s >= 0; s--){ res = min(res, dp[s][b - 1]); for (int v = 0; v < m; v++){ for (int i = 0; i < n; i++){ if ((s >> i & 1)){ for (int u = 0; u < m; u++){ if (edge[v][u] != -1){//因为是s的集合,所以每次要用的时候就取反就相当于是使用了 dp[s & ~(1 << i)][u] = min(dp[s & ~(1 << i)][u], dp[s][v] + (double)edge[v][u] / t[i]); } } } } } } if (res == inf) printf("Impossible\n"); else printf("%.3f\n", res); } int main(){ while (scanf("%d%d%d%d%d", &n, &m, &p, &a, &b) && (n + m + p + a + b)){ memset(t, 0, sizeof(t)); for (int i = 0; i < n; i++) scanf("%d", t + i); memset(edge, -1, sizeof(edge)); for (int i = 0; i < p; i++){ int a, b, c; scanf("%d%d%d", &a, &b, &c); edge[a - 1][b - 1] = edge[b - 1][a - 1] = c; } solve(); } return 0; } </cmath></algorithm></cstring></cstdio>

你可能感兴趣的:(POJ2686 状态压缩dp)