链接:http://poj.org/problem?id=2686
题意:
有m个城市,有n张马车票,每张票上有对应的马的数量,从一个城市到另一个城市需要一张马车票,从一个城市到另一个城市的时间为距离除以马的数量。求从a到b所需要的最短的时间。
思路:
用状压dp。定义 s 表示已经用过的车票的集合,u表示现在所在的城市 。
定义dp[s][u] 现在在u处,已经用过的集合为s时所需要的最小的花费。
状态转移:
dp[s|(1<<i)][u]=min(dp[s|(1<<i)][u],dp[s][v]+mp[u][v]/t[i]);
(0<= i < n && i 不属于s && 0 <= v < m)
那么最后的
ans=min(dp[s][b])
(0<= s < 1 << n)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 30
#define INF 0x3f3f3f3f
int mp[M][M];
double dp[1<<9][M];
int t[M];
int n,m,p,a,b;
int main()
{
while(scanf("%d %d %d %d %d",&n,&m,&p,&a,&b) == 5)
{
a--;b--;
if(n == 0) break;
for(int i = 0;i < n;i++) scanf("%d",&t[i]);
for(int i = 0;i < m;i++) fill(mp[i],mp[i]+m,INF);
for(int i = 0;i < p;i++)
{
int u,v,cost;
scanf("%d %d %d",&u,&v,&cost);
u--;v--;
mp[u][v] = mp[v][u] = cost;
}
for(int i = 0;i < 1<<n;i++) fill(dp[i],dp[i]+m,INF);
dp[0][a] = 0;
double ans = INF;
for(int s = 0;s < 1<<n;s++)
{
//printf("debug --- s = %d b = %d dp[s][b] = %f\n",s,b,dp[s][b]);
ans = min(ans,dp[s][b]);
for(int v = 0;v < m;v++)
{
for(int u = 0;u < m;u++)
{
for(int i = 0;i < n;i++) //此处循环顺序无所谓,但先枚举i应该会快
{
if(!((s >> i) & 1) && mp[u][v] != INF)//有路并不属于
dp[s|(1<<i)][u] = min(dp[s|(1<<i)][u],dp[s][v]+(double)mp[u][v]/t[i]);
}
}
}
}
//for(int s = 0;s < 1<<n;s++) ans = min(ans,dp[s][b]);
if(ans == INF) printf("Impossible\n");
else printf("%f\n",ans);
}
return 0;
}