题意:你要去旅行,要经过n个点,每个点最多经过两次,每一条路径有一定的消费,求最小消费。
状态设定很简单。dp[i][j],表示i状态下j是最后到达的城市,不过最多经过两次所以要用三进制的状态0表示不经过,1表示经过一次,2表示经过两次。边界条件显然是开始出发的城市设定为0。接着状态转移就好了,注意预处理,要对每个数的三进制的位置的值处理一下。
Run ID | Submit Time | Judge Status | Pro.ID | Exe.Time | Exe.Memory | Code Len. | Language | Author |
4486291 | 2011-08-24 20:23:33 | Accepted | 3001 | 546MS | 5372K | 1316 B | G++ | xym2010 |
#include<cstdio> #include<cstring> #include<string> #include<iostream> #include<cmath> #include<algorithm> using namespace std; int dig[11]={1,3,9,27,81,243,729,2187,6561,19683,59049}; int bit[59050][11],dp[59050][11],n,m,gp[11][11],maxn[11]; void init() { int j; for(int i=0;i<dig[10];i++) { int tem=i; for(j=0;tem;j++) { bit[i][j]=tem%3; tem/=3; } } } void DP() { memset(dp,0x1f1f1f1f,sizeof(dp)); for(int i=0;i<n;i++) dp[dig[i]][i]=0; int ans=0x1f1f1f1f,flag=1; for(int i=0;i<dig[n];i++) { flag=1; for(int j=0;j<n;j++) { if(bit[i][j]==0) { flag=0; continue; } for(int k=0;k<n;k++) { if(j==k||bit[i][k]==0)continue; int tem=i-dig[j]; if(dp[tem][k]==0x1f1f1f1f||gp[k][j]==-1)continue; dp[i][j]=min(dp[i][j],dp[tem][k]+gp[k][j]); } } if(flag==1) for(int j=0;j<n;j++) if(dp[i][j]!=0x1f1f1f1f) { ans=min(ans,dp[i][j]); } } if(ans==0x1f1f1f1f) printf("-1\n"); else printf("%d\n",ans); } int main() { int x,y,w; while(scanf("%d%d",&n,&m)!=EOF) { memset(gp,-1,sizeof(gp)); init(); for(int i=0;i<m;i++) { scanf("%d%d%d",&x,&y,&w); if(gp[x-1][y-1]==-1||gp[x-1][y-1]>w) gp[x-1][y-1]=gp[y-1][x-1]=w; } DP(); } return 0; }