【题意】标准的旅行商加一句话,每个点最多走两次。
【分析&解题思路】
定义状态:dp【st】【i】 :在状态为 st 时 当前在 i 点的最小花费
转移方程:dp【now】【j】 = min(dp【now】【j】,dp【st】【i】+mp【i】【j】);now是st可以一次转移得到的状态
【AC代码】#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int n,m,ans;
int tri[12]={0,1,3,9,27,81,243,729,2187,6561,19683,59049};
int dig[59050][11]; //dp[state][i]状态state的第i位是什么
int dp[59050][11],edge[11][11];//当前经过i点状态为state的最小花费
int main(){
//Init dig.
for(int i=0;i<59050;i++){
int t=i;
for(int j=1;j<=10;j++){
dig[i][j]=t%3;
t/=3;
if(t==0)break;
}
}
while(~scanf("%d%d",&n,&m)){
memset(edge,INF,sizeof(edge));
memset(dp,INF,sizeof(dp));
int u,v,w;
while(m--){
scanf("%d%d%d",&u,&v,&w);
if(w<edge[u][v]) edge[u][v]=edge[v][u]=w;
}
//Init dp.
for(int i=1; i<=n; i++) dp[tri[i]][i]=0;
ans=INF;
for(int s=0; s<tri[n+1]; s++){
bool ***=true;//判断所有的城市是否被访问了
for(int i=1; i<=n; i++){
if(dig[s][i]==0) ***=false; //还有城市未被访问
if(dp[s][i]==INF) continue; //该状态下城市i还未被访问
for(int j=1; j<=n; j++){
if(i==j) continue;
if(edge[i][j]==INF||dig[s][j]>=2) continue;
int newS = s+tri[j];
dp[newS][j]=min(dp[newS][j],dp[s][i]+edge[i][j]);
}
}
if(***)//如果所有城市都被访问了,可以更新答案
{
for(int j=1;j<=n;j++) ans=min(ans,dp[s][j]);
}
}
if(ans==INF){
puts("-1");
}
else{
printf("%d\n",ans);
}
}
return 0;
}