分析
f[i][j]表示当前已经走过点的集合为i,移动到j的最小权值。所以这个状态转移方程就是找一个中间点k,将已经走过点的集合i中去除掉j(表示j不在经过的点的集合中),然后再加上从k到j的权值(w[k][j])
因为最大有20个点,所以可以用状态压缩表示这20个点是否被用过。(1<<20)
C++ 代码
#include<bits/stdc++.h>
using namespace std;
const int N = 20,M=1<<20;
int n,f[M][N],w[N][N];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&w[i][j]); //存储两点间的权值
memset(f,0x3f,sizeof f); //初始化
f[1][0]=0; //表示刚开始的集合0点
for(int i=0;i<(1<<20);i++) //表示所有点的使用情况
for(int j=0;j<n;j++)
{
if(i>>j & 1)
{
for(int k=0;k<n;k++)
{
if((i-(1<<j)) >> k &1) //把第j个数除去,同时保证k在这个集合中
{
f[i][j]=min(f[i][j],f[i-(1<<j)][k]+w[k][j]); //满足要求,更新最小值
}
}
}
}
printf("%d",f[(1<<n)-1][n-1]); //所有点都在集合中,且在终点n-1的最小值
return 0;
}