POJ 4979 海贼王之伟大航路 状压dp北大ACM/ICPC竞赛训练
Posted zhenghanghu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 4979 海贼王之伟大航路 状压dp北大ACM/ICPC竞赛训练相关的知识,希望对你有一定的参考价值。
该死的题让我想起来艾斯之死...
首先想到dp(i)代表从1到【i表示的这些岛屿】所花的最小时间,然后每次枚举最后一个岛屿以此缩小范围,但发现枚举了最后一个岛屿后没有办法转移,因为不知道倒数第二个岛屿是什么,随着倒数第二个岛屿的不同,时间的增加也会不同,也就是不具备【无后效性】。
因此想到再加一个参数去约束当前问题的状态,dp(i,j)代表1到【i代表的这些点】所需的最少时间,且这趟旅程的最后一个岛屿是j,这样就可转移了,每次枚举倒数第二岛屿;答案就是dp( (1<<n) -1,n )
具体的位运算来判断i有没有包含k岛屿,自己拿笔推一下就行了
1 #include<iostream> 2 #define INF 1000000000 3 using namespace std; 4 5 int a[20][20],n; 6 int memo[66000][20]; 7 8 int dp(int i,int j){//dp[i,j]代表1到【i代表的这些点】所需的最少时间,且这趟旅程到的最后一个点在j 9 if( j==1 && i!=1 ) return memo[i][j] = INF; //只有当旅程只包含1的时候最后一个到的点才能是1 10 if(memo[i][j]!=INF) return memo[i][j]; 11 if( i == 1 && j==1 ) return memo[i][j]=0; 12 //枚举倒数第二个岛屿在哪 13 for(int k=1;k<n;k++){ 14 if(k==j) continue;//倒数第二个岛不能是倒数第一个岛 15 if( i & 1<<(k-1) ) memo[i][j] = min( memo[i][j], dp(i- (1<<(j-1)),k)+a[k][j] ); 16 } 17 return memo[i][j]; 18 } 19 20 int main(){ 21 for(int i=1;i<66000;i++) 22 for(int j=1;j<20;j++) memo[i][j]=INF; 23 24 cin>>n; 25 for(int i=1;i<=n;i++) 26 for(int j=1;j<=n;j++) cin>>a[i][j]; 27 28 //固定起点为1和终点为N 29 cout<<dp( (1<<n)-1,n ); 30 return 0; 31 }
以上是关于POJ 4979 海贼王之伟大航路 状压dp北大ACM/ICPC竞赛训练的主要内容,如果未能解决你的问题,请参考以下文章