题目大意:m个城市,p条双向路,n张车票,上面记录着马的数量,从一个城市到另一个城市都需要用车票,时间为,两个城市之间道路的长度除以车票上马的数量。求从城市a到城市b的最短时间,无法到达输出Impossible
分析:状压DP。状态:dp[S][v],表示的是到达城市v,且剩下的车票的集合为S时的最短时间
状态转移方程:dp[S & ~(1<<i)][u] = min(dp[S & ~(1<<i)][u], dp[S][v] + g[v][u]*1.0/t[i]);
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1111; double dp[maxn][35]; int g[35][35]; int t[10]; int n, m, p, a, b; int main() { while(scanf("%d%d%d%d%d", &n, &m, &p, &a, &b) && n != 0 && m != 0) { for(int i = 0; i < n; i++) scanf("%d", &t[i]); for(int i = 0; i < m; i++) memset(g[i], -1, sizeof(g[i])); for(int i = 0; i < p; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); u--, v--; g[u][v] = w; g[v][u] = w; } for(int i = 0; i < 1<<n; i++) fill(dp[i], dp[i]+m, 100000000.0); dp[(1<<n)-1][a-1] = 0.0; double ans = 100000000.0; for(int S = (1<<n) -1; S >= 0; S--) { ans = min(ans, 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(g[v][u] >= 0) { //使用车票i,从城市v到城市u dp[S & ~(1<<i)][u] = min(dp[S & ~(1<<i)][u], dp[S][v] + g[v][u]*1.0/t[i]); } } } } } } if(ans != 100000000.0) printf("%.3f\n", ans); else printf("Impossible\n"); } return 0; }