标签:
题意:
给n个点m条无向边。
要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小。
思路:
三进制状态压缩DP,0代表走了0次,1,2类推。
第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的。
然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值。
状态转移也一目了然,不废话。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int inf=0x3f3f3f3f; int pho[15][15]; int unit[12]; int dic[60000][11]; int dp[60000][11]; inline void init() { memset(dic,0,sizeof(dic)); unit[0]=1; for(int i=1;i<=11;i++) { unit[i]=3*unit[i-1]; } for(int i=0;i<=59049;i++) { int tmp=i; for(int j=0;tmp;j++) { dic[i][j]=tmp%3; tmp/=3; } } } int main() { int n,m; init(); while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { pho[i][j]=inf; } pho[i][i]=0; } for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); pho[a][b]=pho[b][a]=min(pho[a][b],c); } int ed=1; for(int i=1;i<=n;i++) { ed*=3; } ed--; for(int s=0;s<=ed;s++) { for(int i=1;i<=n;i++) { dp[s][i]=inf; } } bool ok; int ans=inf; for(int s=0;s<=ed;s++) { ok=1; for(int i=1;i<=n;i++) { if(dic[s][i-1]) { if(s==unit[i-1]) { dp[s][i]=0; } else { for(int k=1;k<=n;k++) { if(i!=k&&(dic[s][k-1])) { dp[s][i]=min(dp[s][i],dp[s-unit[i-1]][k]+pho[k][i]); } } } } else { ok=0; } } if(ok) { for(int i=1;i<=n;i++) { ans=min(ans,dp[s][i]); } } } if(ans>=inf) ans=-1; printf("%d\n",ans); } }
标签:
原文地址:http://www.cnblogs.com/tun117/p/4943679.html