题意:
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\n");
}
else {
printf("%.3f\n", 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