题意:
n张票,m个点,p条路(双向),a起点,b终点
X1~Xn:票的权值,耗时=路长/票权
求从a到b的最短时间
思路:
状态压缩dp,dp[s][i]:s为编码后的含票状态,目前在i点,数组t[]存储票的权
转移方程:使用一张车票k到点j:dp[s{k}][j]=min(dp[s][i]+map[j][i]/t[k],dp[s{k}][j])
复杂度:o(2^n*n^2),状压一般都是小数据才能用吧。。TSP问题是NP困难的。。恩
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<math.h> #include<string.h> using namespace std; #define maxn 10 #define maxm 33 #define maxp 910 #define inf 0x3f3f3f3f int n, m, p, a, b;//n票,m点,p路 int map[maxm][maxm]; int t[maxn]; double dp[1<<maxn][maxm];//dp[S][v]:车票集合S,位于v void solve() { for (int i = 0; i < (1 << n); i++) { fill(dp[i], dp[i] + m + 1, inf); } dp[(1 << n) - 1][a] = 0; double res = inf; for (int S = (1 << n) - 1; S >= 0; S--) { res = min(res, dp[S][b]); //cout << res << endl; for (int v = 1; v <= m; v++) { for (int i = 0; i < n; i++) { if (S >> i & 1) { for (int u = 1; u <= m; u++) { if (map[u][v] > 0) { dp[S & ~(1 << i)][u] = min(dp[S & ~(1 << i)][u], dp[S][v] + (double)map[v][u] / t[i]); //cout << dp[S & ~(1 << i)][u] << endl; } } } } } } if (res == inf) { printf("Impossible "); } else { printf("%.3f ", res); } } int main() { while (~scanf("%d %d %d %d %d", &n, &m, &p, &a, &b) && n) { memset(map, -1, sizeof(map)); for (int i = 0; i < n; i++) { scanf("%d", &t[i]); } for (int i = 1; i <= p; i++) { int u, v, w; scanf("%d %d %d", &u, &v, &w); map[u][v] = map[v][u] = w; } solve(); } }
memset写成sizeof(-1)调试了好久。。
一开始写map[u][v]判通畅还写的大于等于。。
好巧啊,所有样例出来全是0