比较简单的 状态压缩DP
注意DP方程转移时,新的状态必然数值上小于当前状态,故最外层循环为状态从大到小即可。
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn = 1 << 10; const int maxm = 31; const int INF = 1 << 29; int n, m, p, a, b; int t[maxm]; int d[maxm][maxm]; //图的邻接矩阵表示(-1表示没有边) //dp[S][v] := 到达剩下的车票集合为S并且现在在城市v的状态所需要的最小花费 double dp[maxn][maxm]; 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 i = (1 << n) - 1; i >= 0; i--){ for (int u = 1; u <= m; u++){ for (int j = 0; j < n; j++){ if (i & (1 << j)){ for (int v = 1; v <= m; v++){ if (d[v][u]){ //使用车票i,从v移动到u dp[i & ~(1 << j)][v] = min(dp[i & ~(1 << j)][v], dp[i][u] + (double)d[u][v] / t[j]); } } } } } } for (int i = 0; i < (1 << n); i++) res = min(res, dp[i][b]); if (res == INF) //无法到达 printf("Impossible "); else printf("%.3f ", res); } int main() { while(scanf("%d%d%d%d%d", &n, &m, &p, &a, &b)!= EOF){ if(!n && !m) break; memset(d, 0, sizeof(d)); for (int i = 0; i < n; i++) scanf("%d", &t[i]); for (int i = 0; i < p; i++){ int u, v, c; scanf("%d%d%d", &u, &v, &c); d[u][v] = d[v][u] = c; } solve(); } return 0; }