题目
https://www.luogu.org/problemnew/show/P3959
思路
用邻接矩阵存边,f[i] 和dis[i]表示已选点状态为i,每个点距离为dis[i]时的最优答案,每次回溯dis[i],枚举一遍根节点,取个min作为答案,这样每个状态最多更新n^2次(大概吧) 总复杂度是n^ (3* 2^n)。
代码
#include<iostream>
#include<cstdio>
const int inf=0x3f3f3f3f;
int n,m,g[20][20],f[10000],dis[20],ans=INF;
int min(int a,int b){return a<b?a:b; }
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;
}