2 4 5 2 1 2 8 2 3 4 3 4 19 4 1 6 2 4 7 2 25 18 1 3 4 12 6 1 3 4 6 2 1 2 5 1 4 4 3 1 1 3 2 1 3 4 1 2 4 10 2 8 3 1 4 4 8 3 1 2
Case #1: 53 Case #2: 14
题意:给定一个带权无向图(n<=50)和图中若干个景点(k<=8)(每个顶点可包含多个景点),..现在要你‘游’这些景点,‘游’过这些景点的条件是你在这个点等上了一定的时间,如果你有fastpass,也就是经过某些点,那么只需要等FT的时间,否则要等T的时间,问从1号点出发完成任务再回到1号点的最少时间。
下面是看了别的人解题报告:
思路,状态压缩dp,f[i][mark][j]表示当前在j这个点,已经‘游’过的点的2进制状态为i,手上有fastpass的2进制为mark的最少时间
则f[i][mark][j] ==> f[i | (1<<p)][new_mark][loc[p]] // p是下一个要去的景点号,loc[p]是他的位置,new_mark是经过loc[p]后新的关于fastpass的2进制状态
同理f[i]mark][j][ => f[i][new_mark][j‘] // 往另外一个点走,不是最‘游’那些点,可以认为有意图地去是拿fastpass。如果mark==new_mark, 这个式子有没有都不影响结果。
#include<stdio.h> #include<queue> #include<vector> using namespace std; const int N =55; const int inf = 999999999; #define mov(a) (1<<(a)) int mapt[N][N],dp[1<<9][1<<9][N],n int P[N],T[N],FT[N],pass[N],k; void init() { for(int j=0; j<mov(k); j++) for(int e=0; e<mov(k); e++) for(int i=0; i<=n; i++) dp[j][e][i]=inf; for(int i=0; i<=n; i++) { pass[i]=0; for(int j=0; j<=n; j++) mapt[i][j]=inf; mapt[i][i]=0; } } void floyd() { for(int e=1; e<=n; e++) for(int i=1; i<=n; i++) if(e!=i) { for(int j=1; j<=n; j++) if(i!=j&&e!=j&&mapt[i][j]>mapt[i][e]+mapt[e][j]) mapt[i][j]=mapt[i][e]+mapt[e][j]; } } int DP() { dp[0][0][1]=0; for(int sta=0; sta<mov(k); sta++) for(int spa=0; spa<mov(k); spa++) for(int i=1; i<=n; i++) if(dp[sta][spa][i]!=inf) { for(int e=0; e<k; e++) if((sta&mov(e))==0) { int cost=((spa|pass[P[e]])&mov(e))>0?FT[e]:T[e]; if(dp[sta|mov(e)][spa|pass[P[e]]][P[e]]>dp[sta][spa][i]+mapt[i][P[e]]+cost) dp[sta|mov(e)][spa|pass[P[e]]][P[e]]=dp[sta][spa][i]+mapt[i][P[e]]+cost; } //去找旅游景点卷 for(int j=1; j<=n; j++) if(pass[j]>0&&dp[sta][spa|pass[j]][j]>dp[sta][spa][i]+mapt[i][j]) dp[sta][spa|pass[j]][j]=dp[sta][spa][i]+mapt[i][j]; } //找答案 int ans=inf; for(int spa=0; spa<mov(k); spa++) for(int i=1;i<=n;i++) if(ans>dp[mov(k)-1][spa][i]+mapt[i][1]) ans=dp[mov(k)-1][spa][i]+mapt[i][1]; return ans; } int main() { int t,cas=0,m,a,b,c; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&k); init(); while(m--) { scanf("%d%d%d",&a,&b,&c); if(mapt[a][b]>c) mapt[a][b]=mapt[b][a]=c; } for(int i=0;i<k;i++) { scanf("%d%d%d%d",&P[i],&T[i],&FT[i],&m); while(m--) { scanf("%d",&a); pass[a]|=1<<i; } } floyd(); printf("Case #%d: %d\n",++cas,DP()); } }
HDU4114 Disney's FastPass(floyd+状态压缩DP)旅游问题升级(难)
原文地址:http://blog.csdn.net/u010372095/article/details/45080965