题意:旅行家要从城市a旅行到城市b,他的手里有n张马车票,使用马车票可以让旅行家在任意一条马路上通行,马车票上印有马匹的数量t[i],并规定道路的长度除以马匹的数量就是通行该路所花的时间。那么旅行家从城市a到b至少需要花多少时间,如果无法通行,输出‘Impossible’
思路:状态压缩dp,设集合S为旅行家手里剩余的马车票,dp[S][v]含义:旅行家还剩余的马车票组成集合S,并且已到达城市v的时候所花的时间总和。若目前已到达城市v,且马车票组成的集合为S,此时使用集合S中的第i张马车票到达城市u,那么状态转移过程可以表示为: dp[S&~(1<<i)][u]=min{dp[S&~(1<<i)][u],dp[s][v]+d[s][v]/t[i]};
状压dp就是状态压缩dp,把选取的状态换成二进制,变成一个整数,这样就是状态压缩。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define mem(x,v) memset(x,v,sizeof(x))
const int INF = 0x3f3f3f3f;
int n,m,p,a,b,x,y,z;
int d[40][40];
double dp[1 << 10][40];
int t[10];
int main(){
while(~scanf("%d%d%d%d%d",&n,&m,&p,&a,&b) && n){
a--; b--;
for (int i = 0; i < n; i++)
scanf("%d",&t[i]);
mem(d,-1);
for (int i = 0; i < p; i++){
scanf("%d%d%d",&x,&y,&z);
d[x-1][y-1] = z;
d[y-1][x-1] = z;
}
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]);
for (int v = 0; v < m; v++)
for (int i = 0; i < n; i++){
if ((s >> i) & 1){ //使用 第 i 张票。
for (int u = 0; u < m; u++){
if (d[v][u] >= 0){ // 找最优结果。
dp[s & ~(1 << i)][u] = min(dp[s & ~(1<<i)][u],dp[s][v]+(double)d[v][u]/t[i]);
}
}
}
}
}
if (res == INF) printf("Impossible\n"); else
printf("%.3lf\n",res);
}
return 0;
}