Traveling by Stagecoach POJ 2686,题解。
作为一名菜鸟,说状压DP,还是有点勉强,顶多做个学习笔记。
首先,什么是DP,状态转移,其实就是从已经确定的状态,到一个状态。
状压DP,我理解的就是 用 一个数的二进制表达状态。 1,表示 有 ,0 表示无
比如 4而进制表示 100 , 说明 3号 位置表示 有 ,其它的都表示没有。
题目 Traveling by Stagecoach POJ 2686
开一个DP【S】[M]. S 是票的使用状况 , M,是在哪一个城市。值就是最小花费。
1. 把一个票都没有用的,起点 标记为0,也就是 DP[1<<n-1][a]==0.
2. 暴力枚举 所有 可以用的票 ,(S>>i)&1 表示第 I 张票可不可以用。
3. 再暴力枚举 当前这个S下所有的 可以到的城市,dp[S][v]!=INF,当前S下v这个城市可不可以到达。
4. 然后再暴力所有 v, 这个城市所有的路,然后使用第 i张票。d[v][u]>=0。V 和u中间的路。
5. 然如果用这张票,走这条路 到目的地的值小就覆盖前面的值S&~(1<<i)使用第i张票后的状态,d[v][u],从 v城市到u城市的路。
dp[S&~(1<<i)][u]=min(dp[S&~(1<<i)][u],dp[S][v]+(double)d[v][u]*1.0/t[i])。
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<stdio.h>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const long long mod=1e9+7;
const int maxn=9;
const int maxm=31;
const int INF=0x7fffffff;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
int n,m,a,b,p,u,v,c;
int t[maxn];
int d[maxm][maxm];
double dp[1<<maxn][maxm];
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
// freopen("123.txt","r",stdin);
while(cin>>n>>m>>p>>a>>b) {
int k=(1<<n)-1;
if(n==0&&m==0&&p==0&&a==0&&b==0)return 0;
for(int i=0; i<n; i++)cin>>t[i];
memset(d,-1,sizeof(d));
while(p--) {
cin>>u>>v>>c;
d[u][v]=c;
d[v][u]=c;
}
for(int i=0; i<=k; i++)fill(dp[i],dp[i]+m+1,INF);
dp[k][a]=0;
double res=INF;
for(int S=k; S>=0; S--) {
res=min(res,dp[S][b]);
for(int i=0; i<n; i++) {
if((S>>i)&1) {
for(v =1; v<=m; v++) {
if(dp[S][v]!=INF) {
for(u=1; u<=m; u++) {
if(d[v][u]>=0) {
dp[S&~(1<<i)][u]=min(dp[S&~(1<<i)][u],dp[S][v]+(double)d[v][u]*1.0/t[i]);
}
}
}
}
}
}
}
if(res==INF) {
printf("Impossible\n");
} else {
printf("%.3f\n",res);
}
}
return 0;
}