码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 4979 海贼王之伟大航路 【状压dp】【北大ACM/ICPC竞赛训练】

时间:2018-07-25 22:46:54      阅读:250      评论:0      收藏:0      [点我收藏+]

标签:是什么   iostream   cin   pre   efi   答案   不同   竞赛   问题   

该死的题让我想起来艾斯之死...

 首先想到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竞赛训练】

标签:是什么   iostream   cin   pre   efi   答案   不同   竞赛   问题   

原文地址:https://www.cnblogs.com/ZhenghangHu/p/9368618.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!