这道题是到最基础的状压dp,外加一个floyid距离问题(最短距离).
大概题意是有个人从1号位置出发,经过其他n-1个位置又回到1号位置,并且要求其他的地方至少都要走一遍,告诉有m条路径,每条路径都有个起点和终点,还有走这条路径需要的花费,最后求走完所有的地方花费最少是多少?
下边来看代码:
#include<iostream>
#include<cstdio>
using namespace std;
#include<cstring>
int a[18][18],dp[18][1<<18];
const int inf=0x3f3f3f3f;
int n,m;
void floyid()//floyid距离,最短距离的求法
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
int u,v,t;
for(int i=1;i<=n;i++)//对距离初始化
{
for(int j=1;j<=n;j++)
a[i][j]=(i==j)?0:inf;
}
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&t);
if(t<a[u][v])a[u][v]=a[v][u]=t;//这里很容易漏掉,因为观察到题目中n和m的范围才发现,这是个陷阱,1<=n<=16,1<=m<=100000,这里的m太大了,也就是路劲数出奇的多,假设所有的地点都用上,路径数最多也就是16*16,不会有10w,所以一定有一些两点之间的路径重复给出,所以要取其中最小的哦。。。
}
if(n==1){cout<<0<<endl;continue;}
floyid();
memset(dp,inf,sizeof dp);
dp[1][1]=0;
for(int s=1;s<(1<<n);s++)
{
for(int i=1;i<=n;i++)
if(s&(1<<i-1))continue;//状态转移的时候,需要这个被转移的地点还没有走过,如果走过了,那么直接就是pass掉了
else {
for(int k=1;k<=n;k++)
if(s&(1<<k-1)){//要求中间的节点k一定已经走过了,只有这样才可以继续由这个中间节点到达最后的状态转移的i节点
dp[i][s|(1<<i-1)]=min(dp[i][s|(1<<i-1)],dp[k][s]+a[k][i]);
}
}
}
// for(int i=1;i<=n;i++)
// {
// cout<<i<<":"<<dp[i][(1<<n)-1]<<endl;
// }
int minn=inf;
for(int i=2;i<=n;i++)//这里是算加上第i个地点回到1的距离,最后取最小的
minn=min(minn,dp[i][(1<<n)-1]+a[i][1]);
printf("%d\n",minn);
}
}