链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001
题意:还是环游地图的问题,只不过这回旅行者对自己有着严格的要求,地图上每个点的经过次数不能超过两次。
思路:依然是状压DP问题,根上一道很像,只不过这次对于每个点来说有三种状态,分别是未经过,经过一次,经过两次。所以要用三进制的数来进行状态压缩,这个关键点想明白了其他的和上一道基本一样了。对于我来说需要注意的是:能够到达某一个点经过了两次的状态的前一个状态是这个点已经经过了一次的状态,而不是从来未经过这个点的状态。
代码:
#include <algorithm> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <ctype.h> #include <iostream> #include <map> #include <queue> #include <set> #include <stack> #include <string> #include <vector> #define eps 1e-8 #define INF (1<<30)-1 #define maxn 100005 #define PI acos(-1.0) #define seed 31//131,1313 typedef long long LL; typedef unsigned long long ULL; using namespace std; int Pow[15]; int cost[15][15]; int dp[59500][15]; void init() { for(int i=0; i<10; i++) { for(int j=0; j<59500; j++) dp[j][i]=INF; } Pow[0]=1; dp[Pow[0]][0]=0; for(int i=1; i<=10; i++) { Pow[i]=Pow[i-1]*3; dp[Pow[i]][i]=0; } for(int i=0; i<10; i++) for(int j=0; j<10; j++) cost[i][j]=INF; return ; } int main() { int n,m,k,pos; LL ans; while(~scanf("%d%d",&n,&m)) { init(); ans=INF; for(int i=0; i<m; i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); if(cost[x-1][y-1]>z) { cost[x-1][y-1]=z; cost[y-1][x-1]=z; } } for(int i=1; i<Pow[n]; i++) { k=i; pos=0; while(k) { if(k%3==1||k%3==2) { for(int ii=0; ii<n; ii++) { if(ii==pos) continue; if(dp[i-Pow[pos]][ii]+cost[ii][pos]<dp[i][pos]) dp[i][pos]=dp[i-Pow[pos]][ii]+cost[ii][pos]; } } k/=3; pos++; } } for(int i=1;i<Pow[n];i++) { bool flag=0; k=i; int t=0; while(k) { t++; if(k%3==0) flag=1; k/=3; } if(flag==0&&t==n) { for(int ii=0;ii<n;ii++) if(dp[i][ii]<ans) ans=dp[i][ii]; } } if(ans!=INF) printf("%I64d\n",ans); else puts("-1"); } return 0; }
时间: 2024-10-13 14:52:26