状态压缩dp,递推方程 :
n很小,考虑状态压缩dp。
d[s][u] 表示现在在城市u, 还剩下集合为s的车票没有用.
d[s\{i}][v] = min( dp[s][u] + d[u][v] / t[i]) 四个变量,很可能需要四重循环,现在确定递推顺序,s逆序推理,由于后序变量是在前一层变量的基础上进行选取,u, v, i的相对循环位置没有影响,随意即可。
#include<cstdio> #include<cmath> #include<stdlib.h> #include<map> #include<set> #include<time.h> #include<vector> #include<queue> #include<string> #include<string.h> #include<iostream> #include<algorithm> using namespace std; #define eps 1e-8 #define INF 0x3f3f3f3f #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define max_n 8 #define max_m 32 int n, m, p, S, T; int t[10]; int d[max_m][max_m]; double dp[1<<max_n][max_m]; void solve() { double res = INF; for(int i=0; i<(1<<n); i++) fill(dp[i], dp[i]+m+1, INF); dp[(1<<n)-1][S] = 0; for(int s=(1<<n)-1; s>=0; s--) { for(int u=1; u<=m; u++) for(int i=0; i<n; i++) if(s>>i & 1) for(int v=1; v<=m; v++) if(d[u][v] != INF) dp[s-(1<<i)][v] = min(dp[s-(1<<i)][v], dp[s][u]+(double)d[u][v]/t[i]); } for(int s=(1<<n)-1; s>=0; s--) res = min(res, dp[s][T]); if(res != INF) printf("%.3lf\n", res); else printf("Impossible\n"); } int main() { while(scanf("%d%d%d%d%d", &n, &m, &p, &S, &T) && n) { memset(d, 0x3f, sizeof(d)); for(int i=0; i<n; i++) scanf("%d", &t[i]); int u, v, w; for(int i=0; i<p; i++) { scanf("%d%d%d", &u, &v, &w); d[u][v] = d[v][u] = w; } solve(); } return 0; } /* 3 4 3 1 4 3 1 2 1 2 10 2 3 30 3 4 20 2 4 4 2 1 3 1 2 3 3 1 3 3 4 1 2 4 2 5 2 4 3 4 1 5 5 1 2 10 2 3 10 3 4 10 1 2 0 1 2 1 8 5 10 1 5 2 7 1 8 4 5 6 3 1 2 5 2 3 4 3 4 7 4 5 3 1 3 25 2 4 23 3 5 22 1 4 45 2 5 51 1 5 99 0 0 0 0 0 */