1.题目描述:点击打开链接
2.解题思路:本题是状压dp。根据题意,可以把当前手中拥有的车票和当前所在的城市看做一个状态,然后进行状态转移。因为票数是在不断减少的,因此构成的图实际上是一个DAG,可以通过简单的dp得到答案。时间复杂度为O(nm^2*2^n)
3.代码:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<complex>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;
const double INF=1e10;
const int N=8+2;
const int M=35;
double dp[1<<N][M];
int n,m,p,a,b;
int dist[M][M];
int num[N];
void print()
{
for(int i=0;i<1<<n;i++)
for(int j=0;j<m;j++)
printf("dp[%d][%d] = %lf\n",i,j,dp[i][j]);
}
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",&num[i]);
int u,v;
memset(dist,-1,sizeof(dist));
for(int i=0;i<p;i++)
{
scanf("%d%d",&u,&v);
u--,v--;
scanf("%d",&dist[u][v]);
dist[v][u]=dist[u][v];
}
for(int i=0;i<1<<n;i++)
fill(dp[i],dp[i]+m,INF);
dp[(1<<n)-1][a-1]=0;
double ans=INF;
for(int S=(1<<n)-1;S>=0;S--)//枚举当前的车票集合
{
ans=min(ans,dp[S][b-1]);
for(int v=0;v<m;v++) //枚举当前所在城市
for(int i=0;i<n;i++) //枚举要用的车票
if(S>>i&1)
{
for(int u=0;u<m;u++)//枚举下一个城市
if(dist[v][u]>=0)
dp[S&~(1<<i)][u]=min(dp[S&~(1<<i)][u],dp[S][v]+(double)dist[v][u]/num[i]);
}
}
if(ans==INF)puts("Impossible");
else printf("%.3lf\n",ans);
}
}