『最短Hamilton路径 状态压缩DP』

状压DP入门


最短Hamilton路径

Description

给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。

Input Format

第一行一个整数n。 接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(一个不超过10^7的正整数,记为a[i,j])。 对于任意的x,y,z,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]>=a[x,z]。

Output Format

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

Sample Input

4
0 2 1 3
2 0 2 1
1 2 0 1
3 1 1 0

Sample Output

4

解析

很容易想到的朴素解法是枚举全排列,时间复杂度\(O(n*!n)\),显然是会\(TLE\)的。注意到\(n<20\),我们考虑状态压缩\(DP\)。设\(f[i][S]\)代表当前遍历状态为\(S\),到了第\(i\)个点的最短长度。如何理解遍历状态\(S\)呢?我们把它当做一个二进制的\(01\)串,从右数第i位为如果为\(0\),就说明节点i没有被遍历到过,如果第\(i\)位为\(1\),则说明节点i被遍历到过了。我们将整个图的遍历状态记为一个二进制数,这就是状态压缩。

那么我们考虑如何\(DP\)。我们将编号记为从\(1\)开始的,那么初始状态就是\(f[1][1]=0\)。
这里我们需要先理解状态的查询和赋值操作:

1.S&(1<<(i-1))代表取出状态S的(从右往左)第i位
2.S|(1<<(i-1))代表将状态S的(从右往左)第i位赋值为1

那么我们就可以得到状态转移方程了:\[f[j][S|(1<<(j-1))]=\min\{f[i][S]+dis[i][j]\}\]
需要满足节点\(j\)未访问,节点\(i\)已经访问过了。

状态的初值一开始均为正无穷,枚举\(S,i,j\)即可转移,时间复杂度\(O(n^2*2^n)\),目标状态为\(f[n][(1<<n)-1]\)。

\(Code:\)

#include<bits/stdc++.h>
using namespace std;
const int N=20;
int n,dis[N+5][N+5],f[N+5][(1<<N)+5],ans=0x3f3f3f3f;
inline void input(void)
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&dis[i][j]);
}
inline void dp(void)
{
    memset(f,0x3f,sizeof f);
    f[1][1]=0;
    for(int S=1;S<(1<<n);S++)
        for(int i=1;i<=n;i++)
            if(S&(1<<(i-1)))
                for(int j=1;j<=n;j++)
                    if( not (S&(1<<(j-1))) )
                        f[j][S|(1<<(j-1))]=min(f[j][S|(1<<(j-1))],f[i][S]+dis[i][j]);

}
int main(void)
{
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    input();
    dp();
    printf("%d\n",f[n][(1<<n)-1]);
}


『最短Hamilton路径 状态压缩DP』

原文地址:https://www.cnblogs.com/Parsnip/p/10357907.html

时间: 2024-10-09 22:09:51

『最短Hamilton路径 状态压缩DP』的相关文章

最短Hamilton路径-状压dp解法

最短Hamilton路径 时间限制: 2 Sec  内存限制: 128 MB 题目描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次. 输入 第一行一个整数n. 接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(一个不超过10^7的正整数,记为a[i,j]). 对于任意的x,y,z,数据保证 a[x,x]=0,a[x,y]=a

完全图的最短Hamilton路径——状压dp

题意:给出一张含有n(n<20)个点的完全图,求从0号节点到第n-1号节点的最短Hamilton路径.Hamilton路径是指不重不漏地经过每一个点的路径. 算法进阶上的一道状压例题,复杂度为O(n^2 * 2^n),还是蛮恐怖的. 设f[i][j]表示当前经过状态为i,且当前在点j所花费的最小代价.其中i是二进制压缩值,从0-n-1位分别表示这个点是否经过了.目标状态为f[2^n - 1][n - 1],那么我们从小到大枚举i,再循环枚举当前点j和上一个状态所在的点k即可. 转移方程:f[i,

Contest Hunter 0103 最短Hamilton路径 - 状压DP

传送门 思路: 1.状态:由于经过的点是一个集合,所以我们用dis[i][j]表示经过的点的状态为i,且当前位于点j时的最短Hamilton路径,其中i为一个二进制整数,用来存储经过的点的情况.为了方便位运算,我们的点的标号为0~n-1. 2.边界:dis[1][0]表示当前在起点0的最短Hamilton路径. 最终答案在dis[(1<<n)-1][n-1],即0~n-1所有点都被经过了一遍,当前在终点n-1的最短Hamilton路径. 3.决策:对于两点i,j,有两种决策:一是直接通过当前求

ACwing91 最短Hamilton路径 状压dp

网址:https://www.acwing.com/problem/content/93/ 题解: 状压之后暴力枚举更新.$dp[i][j]$表示$i$的二进制数中1的位置就是会经过的点,$j$的位置是当前的点.则转移方程是$dp[i][j]=min(dp[i][j],dp[i\oplus (1<<j)][k]+dis[k][j])$,其中$i\oplus (1<<j)$是二进制状态$i$去掉第$j$条边,即从一个没有与$j$直接连边的状态从$k$到$j$进行松弛,最后判断一下有边

# 最短Hamilton路径(二进制状态压缩)

最短Hamilton路径(二进制状态压缩) 题目描述:n个点的带权无向图,从0-n-1,求从起点0到终点n-1的最短Hamilton路径(Hamilton路径:从0-n-1不重不漏的每个点恰好进过一次) 题解:二进制状态压缩算法\(O(2^n*n^2)\),需要记录当前经过了哪些点,当前在哪个位置.\(f[i][j]\) ? \(i\)转化为二进制每一位代表是否经过该点,\(j\)表示当前位于j这个点 #include <iostream> #include <cstring> u

P1171 售货员的难题 - 状压DP【最短Hamilton路径】

P1171 售货员的难题 Sol: 最短Hamilton路径,经典的NPC问题,小数据可以通过状压DP 实现. 状态:\(f[i][j]\)表示当前在第i号点,且已经过的点的状态为j 时的最短Hamilton路径. 阶段:若以点为阶段,由于会从点i转移到点i+1,还可能从i+1转移到i-1,不具有无后效性,因此我们考虑以二进制状态为阶段进行转移. 决策:考虑由哪一个点转移而来. 转移:\(f[i][j]=\max \limits_{i\&(1<<i)\&\&i\&

Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖

题目来源:Light OJ 1406 Assassin`s Creed 题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问题 这里可能有环 所以要缩点 可是看例子又发现 一个强连通分量可能要拆分 n最大才15 所以就状态压缩 将全图分成一个个子状态 每一个子状态缩点 求最小路径覆盖 这样就攻克了一个强连通分量拆分的问题 最后状态压缩DP求解最优值 #include <cstdio> #include <cstri

最短Hamilton路径 数位dp

最短Hamilton路径 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 21; 4 int dp[1<<maxn][maxn]; 5 int maps[maxn][maxn]; 6 int main() { 7 int n; cin >> n; 8 for (int i = 0; i < n; i++) 9 for (int j = 0; j < n; j++) 10

最短Hamilton路径

题目描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次. 输入 第一行一个整数n. 接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(一个不超过10^7的正整数,记为a[i,j]). 对于任意的x,y,z,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]>=a[x,z]. 输出 一个整数