题目大意:有n个城市,m条边,你可以从任意一个城市出发,每个城市可以经过最多2次,且每个城市必须经过
求最短路径,如果没有这样的路,输出-1;
结题思路;此题N值比较小,是典型的状压dp特点,他仍然是一个np问题,只不过每个城市可以经过2次,那么我们
将二进制改为三进制求解即可,dp[s][i]仍然表示s状态下的终点为i
转移方程 dp[ss][j]=min(dp[ss][j],dp[s][i]+ma[i][j])
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define inf 0x3fffffff
int dp[59050][15],dis[59050][15];
int ma[15][15],aa[15];
void init()
{
aa[1]=1;
for(int i=2;i<=15;i++)
{
aa[i]=aa[i-1]*3;
}
}
void init1()
{
for(int i=1;i<=59050;i++)
{
int t=i;
for(int j=1;j<=10;j++)
{
dis[i][j]=t%3;
t=t/3;
if(t==0)break;
}
}
}
int main()
{
init();
init1();
int n,m,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF)
{
int ans=inf;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
ma[i][j]=inf;
}
}
for(int 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(int i=0;i<=59050;i++)
{
for(int j=1;j<=11;j++)
dp[i][j]=inf;
}
for(int i=1;i<=n;i++)//当前状态下只有i点被走过,即起点为i点
dp[aa[i]][i]=0;
for(int s=0;s<aa[n+1];s++)
{
int fg=1;//fg的作用是判断s状态下是否所有点都走过
for(int i=1;i<=n;i++)
{
if(dis[s][i]==0)
{
fg=0;
continue;
}
for(int j=1;j<=n;j++)
{
if(i==j)continue;
if(ma[i][j]==inf||dis[s][j]>=2)continue;
int ss=s+aa[j];
dp[ss][j]=min(dp[ss][j],dp[s][i]+ma[i][j]);
}
}
if(fg)
{
for(int j=1;j<=n;j++)
{
ans=min(ans,dp[s][j]);
}
}
}
if(ans==inf)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}