题意:
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;
} 
京公网安备 11010502036488号