这道题是一个状压,汤神说爆搜写就行,我这个小蒟蒻只会写递推DP,还莫名WA掉一组。后来想了一下,因为这道题加路径的时候,是加上L*K的,L是边权,K是从起点到当前的点经过的点的数量。如果有一种情况,由上一个状态到达了当前的这个状态,求出的值和当前的ans相等的话,那么递推的时候就没法儿更新(按照我这个彩笔的写法),但是当前这个状态的每个点的K值和之前最优值的不一定一样。那么这时候不好判断最优值。所以这道题,使用记忆化搜索方便一些,我们使用dfs+回溯就可以。
上代码
:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 2147483647
int n,m,g[20][20],f[10000],dis[20],ans=INF;
void find(int x)
{
for(int i=1;i<=n;i++)
if((1<<(i-1))&x)
{
for(int j=1;j<=n;j++)
if(((1<<(j-1))&x)==0&&g[i][j]!=INF)
{
if(f[x|(1<<(j-1))]>f[x]+dis[i]*g[i][j])
{
int tmp=dis[j];
dis[j]=dis[i]+1;
f[x|(1<<(j-1))]=f[x]+dis[i]*g[i][j];
find(x|(1<<(j-1)));
dis[j]=tmp;
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
g[i][j]=INF;
int u,v,z;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&z);
g[u][v]=min(g[u][v],z);
g[v][u]=min(g[v][u],z);
}
for(int o=1;o<=n;o++)
{
for(int i=1;i<=n;i++) dis[i]=INF;
for(int i=1;i<=(1<<n)-1;i++) f[i]=INF;
dis[o]=1;
f[1<<(o-1)]=0;
find(1<<(o-1));
ans=min(ans,f[(1<<n)-1]);
}
printf("%d",ans);
return 0;
}