最短hamilton路径问题已经被证明是一个NPhard问题,求解最短路径复杂,所以要对问题进行状态压缩,我们用来表示以节点j为结尾时所经过的节点。表示方式为将第一维的i以二进制来进行表示,每一位的1或0表示该点是否被走过,所以我们第一维有种状态。我们以8个节点为例,第一个节点为0,最后一个节点为7,我们所需要求的最终状态即为。
将255转化为二进制表示即为011111111,可以发现该状态为从0到7所有节点都被遍历且以7为结尾,说明我们遍历了图中所有的节点一次并且来到了终点7。
ACcode
// #pragma GCC optimize (2)
// #pragma G++ optimize (2)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <unordered_map>
#include <map>
#include <bitset>
#include <set>
#define endl '\n'
#define int long long
#define lowbit(x) x &(-x)
#define rep(i, a, n) for (int i = a; i <= n; i++)
const double esp = 1e-5;
using namespace std;
void TLE() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); }
const int N=20,M=1<<20;
int f[M][N],weight[N][N];
int n;
void solve()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>weight[i][j];//保存图中信息
memset(f,0x3f,sizeof(f));
f[1][0]=0;//遍历过1号节点且以0为终点的路径个数为1
for(int i=0;i<1<<n;i++)//遍历所有pow(2,n)个状态
for(int j=0;j<n;j++)
if(i>>j&1)//判断该状态是否合法经历过j并且以j为结尾才为合法状态,只需判断i的二进制表示第j个位置是否为1
for(int k=0;k<n;k++)
{
if(i-(1<<j)>>k&1)//判断该更新是否合法
{
f[i][j]=min(f[i][j],f[i-(1<<j)][k]+weight[k][j]);
}
}
cout<<f[(1<<n)-1][n-1]<<endl;//输出便利过所有节点并且以n-1为结尾的最路径
}
signed main()
{
TLE();
int T;T = 1;
// int T;cin>>T;
while (T--)
solve();
return 0;
}