描述:

m 个 城 市 有 p 条 双 向 道 路 。 道 路 的 花 费 是 道 路 的 距 离 / 票 上 的 数 字 。 给 出 n 张 票 , 求 a − > b 的 最 短 路 m个城市有p条双向道路。道路的花费是道路的距离/票上的数字。给出n张票,求a->b的最短路 m个城市有p条双向道路。道路的花费是道路的距离/票上的数字。给出n张票,求a−>b的最短路。

开始本来想老套路把城市状态来压缩,但城市最多可以有30个,故考虑把船票压缩。

定义 d p [ i ] [ j ] dp[i][j] dp[i][j]为用的船票状态为i此时到达j城市的最短路

初始化为dp[0][a]=0,正常转移即可

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
int n,m,p,a,b;
double d[39][39],v[39],dp[1<<9][39];
int main()
{
while(cin>>n>>m>>p>>a>>b&&(n+m))
{
a--,b--;
double ans=1e18;
for(int i=0;i<=30;i++)for(int j=0;j<=30;j++)d[i][j]=9999999999999;
for(int i=0;i<n;i++) cin>>v[i];
for(int i=0;i<p;i++)
{
int l,r;double w;
cin>>l>>r>>w;l--,r--;
d[l][r]=d[r][l]=w;
}
for(int i=0;i<(1<<9);i++)for(int j=0;j<=m;j++)dp[i][j]=99999999999;
dp[0][a]=0;
int len=(1<<n);
for(int i=0;i<len;i++)
{
for(int j=0;j<n;j++)
{
if(i&(1<<j))//这次用哪张票
{
for(int q=0;q<m;q++)//当前在q城市
{
for(int k=0;k<m;k++)//从k城市转移而来
{
if(q==k) continue;
// dp[i][q]=min(dp[i][q],dp[i-(1<<j)][k]+d[q][k]/v[j]);
dp[i][k]=min(dp[i][k],dp[i-(1<<j)][q]+d[q][k]/v[j]);
if(k==b)
ans=min(ans,dp[i][k]);
}
}
}
}
}
if(ans>=99999999998) cout<<"Impossible"<<endl;
else printf("%.3lf\n",ans);
}
}