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竞赛训练的主要内容,如果未能解决你的问题,请参考以下文章

百练4124 海贼王之伟大航路

Bailian4124 海贼王之伟大航路DP

ACM 海贼王之伟大航路(深搜剪枝)

4124:海贼王之伟大航路(dfs)

搜索:估值型剪枝

搜索:估值型剪枝