题意:一个人要旅行,他要去n个地方,且这n个地方每个地方最多可以走2次;
给m条路径,寻问最短花费
很明显的状态压缩,但是要求每个点最多只能走两次,就没办法标记当前点走过或是没走过,只能用三进制来表示
1代表地点1被走过一次、
2代表地点1被走过两次、
3(即10)代表地点2被走过一次、
4(即11)代表地点1被走过一次,地点2被走过一次、
5(即12)代表地点1被走过两次,地点2被走过一次、
附AC代码
#include<stdio.h> #include<string.h> int dis[15],dp[80000][15],dpp[80000][15]; int map[15][15]; int min1(int a,int b) { if(a<b) return a; return b; } int main() { int i,j,n,m,k; j=1; for(i=1;i<=11;i++) { dis[i]=j; j*=3; } for(i=0;i<dis[11];i++) { k=i; for(j=1;j<=11;j++) { dpp[i][j]=k%3; k/=3; } } while(scanf("%d%d",&n,&m)!=EOF) { int sum; memset(map,127,sizeof(map)); sum=map[0][0]; int cnt=map[0][0]; while(m--) { scanf("%d%d%d",&i,&j,&k); if(k<map[i][j])//重边 map[j][i]=map[i][j]=k; } memset(dp,127,sizeof(dp)); for(i=1;i<=n;i++) { dp[dis[i]][i]=0;// } for(k=0;k<dis[n+1];k++) { int tot=1; for(i=1;i<=n;i++) { if(dpp[k][i]==0) tot=0; if(dp[k][i]==cnt)continue; for(j=1;j<=n;j++) { if(i==j)continue;//相同的地点不用更新 if(dpp[k][j]>=2)continue;//两次不用更新,因为不能再走了 if(map[i][j]==cnt)continue;//map[i][j]==cnt表示没有从i到j的路故不用更新 int l=k+dis[j]; dp[l][j]=min1(dp[l][j],dp[k][i]+map[i][j]); } } if(tot) { for(i=1;i<=n;i++) { sum=min1(sum,dp[k][i]); } } } if(sum==cnt) sum=-1; printf("%d\n",sum); } return 0; }
时间: 2024-10-14 06:49:57