状态压缩dp,递推方程 :
n很小,考虑状态压缩dp。
d[s][u] 表示现在在城市u, 还剩下集合为s的车票没有用.
d[s\{i}][v] = min( dp[s][u] + d[u][v] / t[i]) 四个变量,很可能需要四重循环,现在确定递推顺序,s逆序推理,由于后序变量是在前一层变量的基础上进行选取,u, v, i的相对循环位置没有影响,随意即可。
#include<cstdio>
#include<cmath>
#include<stdlib.h>
#include<map>
#include<set>
#include<time.h>
#include<vector>
#include<queue>
#include<string>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define max_n 8
#define max_m 32
int n, m, p, S, T;
int t[10];
int d[max_m][max_m];
double dp[1<<max_n][max_m];
void solve()
{
double res = INF;
for(int i=0; i<(1<<n); i++)
fill(dp[i], dp[i]+m+1, INF);
dp[(1<<n)-1][S] = 0;
for(int s=(1<<n)-1; s>=0; s--)
{
for(int u=1; u<=m; u++)
for(int i=0; i<n; i++)
if(s>>i & 1)
for(int v=1; v<=m; v++)
if(d[u][v] != INF)
dp[s-(1<<i)][v] = min(dp[s-(1<<i)][v], dp[s][u]+(double)d[u][v]/t[i]);
}
for(int s=(1<<n)-1; s>=0; s--)
res = min(res, dp[s][T]);
if(res != INF)
printf("%.3lf\n", res);
else printf("Impossible\n");
}
int main()
{
while(scanf("%d%d%d%d%d", &n, &m, &p, &S, &T) && n)
{
memset(d, 0x3f, sizeof(d));
for(int i=0; i<n; i++)
scanf("%d", &t[i]);
int u, v, w;
for(int i=0; i<p; i++)
{
scanf("%d%d%d", &u, &v, &w);
d[u][v] = d[v][u] = w;
}
solve();
}
return 0;
}
/*
3 4 3 1 4
3 1 2
1 2 10
2 3 30
3 4 20
2 4 4 2 1
3 1
2 3 3
1 3 3
4 1 2
4 2 5
2 4 3 4 1
5 5
1 2 10
2 3 10
3 4 10
1 2 0 1 2
1
8 5 10 1 5
2 7 1 8 4 5 6 3
1 2 5
2 3 4
3 4 7
4 5 3
1 3 25
2 4 23
3 5 22
1 4 45
2 5 51
1 5 99
0 0 0 0 0
*/