题目大意:给你一张图,有n个节点,有m条边,每条边都有它的权值,你的任务是访问每个顶点不超过两次,但每个点一定要被访问过一次,问你最少花费多少;
题目解析:首先看到n这么小,肯定是状态压缩了,dp[i][j]表示以第i个点为结束点,j为状态序列的时候所表示的最少花费,注意这里的状态表示要用3进制,这样就能表示两次了,状态转移的时候只要枚举即可,初始条件只要初始每个点作为起始点即可;
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#define inf 0x3fffffff
using namespace std;
int mo[15][59051],dp[15][59051];
int main()
{
int n,m,ma[16][16],thd[16],a,b,c,i,j,k,temp,flag,ans,s;
memset(mo,0,sizeof(mo));
for(i=0;i<=59050;i++)
{
temp=i;
for(j=1;j<=10;j++)
{
mo[j][i]=temp%3;
temp=temp/3;
if(temp==0)
break;
}
}
thd[1]=1;
for(i=2;i<=15;i++)
{
thd[i]=thd[i-1]*3;
}
while(scanf("%d%d",&n,&m)!=EOF)
{
ans=inf;
for(i=0;i<=11;i++)
{
for(j=0;j<=59050;j++)
{
dp[i][j]=inf;
}
}
for(i=0;i<=12;i++)
{
for(j=0;j<=12;j++)
ma[i][j]=inf;
}
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(c<ma[a][b])
ma[a][b]=ma[b][a]=c;
}
for(i=1;i<=n;i++)
dp[i][thd[i]]=0;
for(j=0;j<thd[n+1];j++)
{
flag=1;
for(i=1;i<=n;i++)
{
if(mo[i][j]==0)
{
flag=0;
continue;
}
for(k=1;k<=n;k++)
{
if(k==i) continue;
if(ma[i][k]==inf||mo[k][j]>=2) continue;
s=j+thd[k];
dp[k][s]=min(dp[k][s],dp[i][j]+ma[i][k]);
}
}
if(flag==1)
{
for(i=1;i<=n;i++)
{
ans=min(ans,dp[i][j]);
}
}
}
if(ans==inf)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}