HDU 3001 Travelling(状态压缩DP+三进制)
Posted Yeader
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 3001 Travelling(状态压缩DP+三进制)相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001
题目大意:有n个城市,m条路,每条路都有一定的花费,可以从任意城市出发,每个城市不能经过两次以上,要求经过所有城市并且花费最少,求出最小花费。
解题思路:三进制的状态压缩DP,跟二进制还是有一点不一样的,因为三进制没有直接的位运算,还要自己先做处理利用num[i][j]记录数字i各位的三进制表示方便计算,其他的就跟二进制状态压缩没有太大区别了。还有注意:
①开始要将n个起点初始化,dp[bit[i]][i]=0
②有重边,要去重
代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<queue> 5 #include<cstring> 6 using namespace std; 7 const int INF=0x3f3f3f3f; 8 const int N=6e4+5; 9 10 int n,m,ans; 11 int map[15][15]; 12 int dp[N][15]; 13 int bit[15]={1,3,9,27,81,243,729,2187,6561,19683,59049}; 14 int num[N][15]; 15 16 //计算所有数字10位以内三进制表示 17 void make_tab(){ 18 for(int i=0;i<bit[10];i++){ 19 int b=i; 20 for(int j=0;j<10;j++){ 21 num[i][j]=b%3; 22 b/=3; 23 } 24 } 25 } 26 27 int main(){ 28 make_tab(); 29 while(~scanf("%d%d",&n,&m)){ 30 memset(map,0x3f,sizeof(map)); 31 memset(dp,0x3f,sizeof(dp)); 32 int ans=INF; 33 for(int i=1;i<=m;i++){ 34 int a,b,c; 35 scanf("%d%d%d",&a,&b,&c); 36 a--,b--; 37 //去重边 38 map[a][b]=min(map[a][b],c); 39 map[b][a]=min(map[b][a],c); 40 } 41 for(int i=0;i<n;i++) 42 dp[bit[i]][i]=0;//对每个点定位初始点0 43 44 for(int i=0;i<bit[n];i++){ 45 bool flag=true;//表示所有位都是>=1,也就是每个城镇都走过了 46 for(int j=0;j<n;j++){ 47 if(num[i][j]==0) 48 flag=false; 49 if(dp[i][j]==INF)//判断是否走到j点 50 continue; 51 for(int k=0;k<n;k++){ 52 //注意这个num[i][k]>=2,因为如果i状态在k点已经走过两次了显然是不能继续往下走的 53 if(j==k||num[i][k]>=2||map[j][k]==INF) 54 continue; 55 int next=i+bit[k];//从j点走到k点 56 dp[next][k]=min(dp[next][k],dp[i][j]+map[j][k]); 57 } 58 } 59 //如果所有城镇都走了一遍则可以找出最小值 60 if(flag){ 61 for(int j=0;j<n;j++) 62 ans=min(ans,dp[i][j]); 63 } 64 } 65 if(ans==INF) 66 puts("-1"); 67 else 68 printf("%d\n",ans); 69 } 70 return 0; 71 }
以上是关于HDU 3001 Travelling(状态压缩DP+三进制)的主要内容,如果未能解决你的问题,请参考以下文章
HDOJ--3001--Travelling(状态压缩DP+bfs)
HDU 3001 Travelling (状压DP + BFS)
hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp