【题意】标准的旅行商加一句话,每个点最多走两次。

【分析&解题思路】

定义状态: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;
}