题目大意:有一个旅行家计划旅行,他所在城市有m个城市,在城市之间有p条路径。从某个城市沿着某条道路到相邻的城市需要坐马车,而乘坐马车需要车票。一张车票只能通过一条路,每张车票都记有马的数量。从一个城市到另一个城市所需要的时间是城市之间道路的长度除以马的数量的结果。这位旅行家一共有n张车票,第i张车票上的马的数量是ti。求从城市a到城市b的最短时间。无法到达输出impossible。
思路:暴力搜索复杂度太高,可以使用状态压缩DP的方法,利用二进制压缩用S来表示车票的集合。
dp[S][v]:剩余的车票集合为S且当前所在城市为v所需要的最小花费。
边界条件: dp[(1<<n)-1][a-1] = 0(n为车票数量,城市原本是1~m,此处是表示为0~m-1)m-1
状态转移方程 : dp[S & (1<<k)][u] = min(dp[S & (1<<k)][u] , dp[S][v] + (double)G[v][u]/t[i]) (求从当前v到达u的最优策略)
(k为枚举S中的每一张车票)。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include<cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <cctype>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i(a); i <= (b); ++i)
#define dec(i, a, b) for(int i(a); i >= (b); --i)
#define MP make_pair
const double INF = 1e8;
const int N = 100000 + 10;
const int M = 10000 + 10;
const int Q = 1000 + 10;
const int A = 100 + 10;
const int maxn = 30 + 5;
int n,m,a,b;
int t[maxn],G[maxn][maxn];
double dp[1 << 10][maxn];
void solve(void){
rep(i,0,(1<<n)-1){
fill(dp[i],dp[i]+m,INF);
}
dp[(1<<n)-1][a-1] = 0;
double res = INF;
dec(S,(1<<n)-1,0){
res = min(res,dp[S][b-1]);
rep(v,0,m-1){
rep(i,0,n-1){
if((S>>i) & 1){
rep(u,0,m-1){
if(G[v][u] >= 0){
dp[S & ~(1<<i)][u] = min(dp[S & ~(1<<i)][u] , dp[S][v] + (double)G[v][u]/t[i]);
}
}
}
}
}
}
if(res == INF){
printf("Impossible\n");
}
else{
printf("%.3f\n",res);
}
}
int main(){
int p;
while(~scanf("%d%d%d%d%d",&n,&m,&p,&a,&b)){
if(!n && !m && !p && !a && !b) break;
memset(G,-1,sizeof(G));
rep(i,0,n-1) scanf("%d",&t[i]);
rep(i,1,p){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
G[x-1][y-1] = G[y-1][x-1] = w;
}
solve();
}
return 0;
}
组
6