AcWing 最短Hamilton距离 (状压DP)

题目描述

给定一张 n 个点的带权无向图,点从 0∼n−1 标号,求起点 0 到终点 n−1 的最短 Hamilton 路径。

Hamilton 路径的定义是从 0 到 n1 不重不漏地经过每个点恰好一次。

输入格式

第一行输入整数 n

接下来 n 行每行 n 个整数,其中第 i 行第 j 个整数表示点 i 到 j 的距离(记为 a[i,j])。

对于任意的 x,y,z数据保证 a[x,x]=0a[x,y]=a[y,x]a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]a[x,z]a[x,y]+a[y,z]≥a[x,z]。

输出格式

输出一个整数,表示最短 Hamilton 路径的长度。

 

状压DP题,也是一道妙题啊......

因为要不重不漏经过所有点,1<<n 可以表示所有情况,也就是对应每种状态,f[i][j]表示在当前i状态下目前到达j的最短路。

方程:f[i][j]=min{f[i^(1<<j)][k]+a[k][j]} 其中0<=k<n且((i>>j)&1)=1   i^(1<<j)表示不经过j这个点,而当前状态i可能是从任意一点k转移过来的。复杂度大概是n2*2n

 这个复杂度是固定的,可以用于解决n<=21的问题。

代码很短,但不好想。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[21][21],f[1<<20][20];
 4 
 5 int main(){
 6     int n;cin>>n;
 7     for(int i=0;i<n;i++)
 8         for(int j=0;j<n;j++)
 9         cin>>a[i][j];
10     memset(f,0x3f,sizeof(f));
11     f[1][0]=0;
12     for(int i=0;i<(1<<n);i++)
13         for(int j=0;j<n;j++) if(i>>j&1)
14             for(int k=0;k<n;k++) if((i^1<<j)>>k&1)
15                 f[i][j]=min(f[i][j],f[i^1<<j][k]+a[k][j]);
16                 
17     cout<<f[(1<<n)-1][n-1];
18 } 

 

posted @ 2022-04-08 16:40  YHXo  阅读(55)  评论(0)    收藏  举报