题目很长就不直接粘贴复制过来了
题意:
给你n张车票,m个城市,p条边(由x城市到y城市的z长度),a是起点,b是终点。
你每走一条路就会花掉一张车票,而这条路上的时间花费为路长/票的价值。
如果能由起点a到达终点b就输出最小的时间花费,否则输出Impossible。
题解:
由于n的数据范围很小,最大为8,很明显就可以把每张票的状态作为状压的入手点。1表示用过这张票,0表示没有。
那么我们就可以直接暴力枚举总的状态(1<<n) ,枚举每张车票,枚举每个顶点和起点。
然后用下面这个状态转移方程代入即可解决:
dp[i|(1<<j)][v]=min(dp[i|(1<<j)][v],dp[i][u]+1.0*dis[u][v]/ti[n-j]);
具体代码 + 解析
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 50;
const int mod= 10007;
int t,n,m,p,a,b,x,y,z,sum,mx,cnt,idx;
int dis[maxn][maxn],ti[maxn]; //路长与票价
double dp[500][maxn];
double ans;
int main()
{
while(scanf("%d %d %d %d %d",&n,&m,&p,&a,&b),n+m+p+a+b)
{
for(int i=0;i<n;i++)
scanf("%d",&ti[i]);
memset(dis,-1,sizeof dis); //记得初始化为-1
for(int i=1;i<=p;i++) //邻接矩阵存图
{
scanf("%d %d %d",&x,&y,&z);
dis[x][y]=z;
dis[y][x]=z;
}
for(int i=0;i<500;i++)
for(int j=0;j<maxn;j++)
dp[i][j]=inf;
dp[0][a]=0;
ans=inf;
for(int i=0;i<(1<<n);i++) //枚举总的状态
{
for(int j=0;j<n;j++) //枚举每张车票
{
if(i&(1<<j))continue;
for(int u=1;u<=m;u++) //枚举顶点
{
for(int v=1;v<=m;v++) //枚举终点
{
if(dis[u][v]>=0)
dp[i|(1<<j)][v]=min(dp[i|(1<<j)][v],dp[i][u]+1.0*dis[u][v]/ti[j]);
}
}
}
ans = min(ans,dp[i][b]); //记录下到终点的最小时间花费
}
if(ans==inf)
puts("Impossible");
else
printf("%.3lf\n",ans);
}
return 0;
}