题意:
n 个城市已及 m 条路 以及对应路费 c,要求遍历所有城市最少的路费,每个城市不能超过2次。
思路:
三进制位表示一个城市被走过的次数,三进制没有位运算,可以预处理三进制位每一位的权值以及每个十进制数的三进制表示。
状态方程:表示访问中所有的点后最后到达城市(感觉紫书上对旅行商的解析不太好)
转移方程:
Code:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include <vector> #include<map> #include<set> #include<utility> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } int n,m; int bit[12]={0,1,3,9,27,81,243,729,2187,6561,19683,59049}; //三进制每一位的权值 int tri[60000][11];//记录每个数的三进制数 int dp[11][60000]; int graph[11][11]; void make_trb() { for(int i=0;i<59050;++i) { int t=i; for(int j=1;j<=10;++j) { tri[i][j]=t%3; t/=3; } }//共3^10=59049种状态 } int comp_dp() { int ans=inf; memset(dp,inf,sizeof dp); for(int i=0;i<=n;++i)//初始化超人把他送到任意位置开始时的值 dp[i][bit[i]]=0; for(int i=0;i<bit[n+1];++i) { int flag=1;//表示每个城市都遍历了至少一次 for(int j=1;j<=n;++j) { if(tri[i][j]==0) { flag=0; continue; } if(i==j) continue; for(int k=1;k<=n;++k) { int l=i-bit[j]; if(tri[i][k]==0) continue; dp[j][i]=min(dp[j][i],dp[k][l]+graph[k][j]); }//枚举下到达k的点 }//历遍所有终点 if(flag) for(int j=1;j<=n;++j) ans=min(ans,dp[j][i]); } return ans; } int main() { make_trb(); while(cin>>n>>m) { memset(graph,inf,sizeof graph); while(m--) { int a,b,c; cin>>a>>b>>c; if(c<graph[a][b]) graph[a][b]=graph[b][a]=c;//去重边 } int ans=comp_dp(); if(ans==inf) cout<<"-1"<<endl; else cout<<ans<<endl; } return 0; }