标签:状压dp
2 1 1 2 100 3 2 1 2 40 2 3 50 3 3 1 2 3 1 3 4 2 3 10
100 90 7
看了别人的思路,自己写出来了:)。这题和poj3311差不多,但是不能用floyd处理,因为它有访问次数限制,最多相同的地方访问两次,至少一次,所以为了存储状态,我们可以用三进制表示,1代表访问一次,2代表访问2次。动态转移方程也和之前的差不多,为dp[s][i]=min(dp[s][i],dp[s-san[i-1]][j]+dis[j][i])。最后的结论要在访问过程中产生,如果当前所枚举的状态符合用三进制表示后每一位的数都大于0,那么就表示都访问到了,就可以和所求的结果ans比,如果比ans小就更新。
#include<stdio.h> #include<string.h> #define inf 88888888 int dis[15][15],dp[200000][15],wei[15],num,t; int san[15]={1,3,9,27,81,243,729,2187,6561,19683,59049,177147}; int min(int a,int b){ return a<b?a:b; } void zhuanhua(int x) { int i,j; num=0,t=0; while(x>0){ if(x%3>0)num++; wei[++t]=x%3; x=x/3; } } int main() { int n,m,i,j,a,b,c,s,ans; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ dis[i][j]=inf; } } for(i=1;i<=m;i++){ scanf("%d%d%d",&a,&b,&c); if(dis[a][b]>c)dis[a][b]=dis[b][a]=c; } ans=inf; for(s=1;s<san[n+1];s++){ for(i=1;i<=n;i++){ dp[s][i]=inf; } } for(s=1;s<san[n+1];s++){ zhuanhua(s); for(i=1;i<=n;i++){ if(t>=i && wei[t]>0){ if(s==san[i-1]){ dp[s][i]=0; } else{ for(j=1;j<=n;j++){ if(j!=i && wei[j]>0){ dp[s][i]=min(dp[s][i],dp[s-san[i-1]][j]+dis[j][i]); if(num==n){ ans=min(ans,dp[s][i]); } } } } } } if(ans==0)break; } if(ans==inf)printf("-1\n"); else printf("%d\n",ans); } }
标签:状压dp
原文地址:http://blog.csdn.net/kirito_acmer/article/details/46593787