[动态规划]-------状压DP

旅行商问题

给定一个 N N N 个顶点组成的带权图 G ( V , E ) G(V, E) G(V,E),要求从顶点 1 出发,经过每个顶点恰好一次后再返回到顶点1,问所经过的边的总权值最小值是多少。

旅行商问题(TSP,Traveling Salesman Problem)是一个著名的 N P NP NP难 问题,没有已知的多项式时间的算法,不过我们还是可以通过设计算法来解决规模较小的 T S P TSP TSP 问题。

容易想到朴素做法的时间复杂度为 O ( n ! ) O(n!) O(n!) 级别,即遍历路径的所有可能情况。状态压缩动态规划可以在指数级时间内求解TSP问题,这也是一个入门状压DP的经典问题。

状压DP解决TSP问题

假设现在已经访问过的顶点集合为 S S S ,当前所在的顶点为 v v v,用 D P [ S ] [ v ] DP[S][v] DP[S][v] 表示从 v v v 出发访问剩余所有顶点,最终回到顶点1的路径的权重的最小值。从 v v v 出发可以转移到任何一个不在 S S S 中的顶点u,因此有如下转移方程:
d p [ V ] [ 0 ] = 0 d p [ S ] [ v ] = m i n { d p [ S   ∪   u ] [ u ] + d ( v , u )   ∣   u ∉ S } dp[V][0] = 0 \\ dp[S][v]=min\{dp[S\ \cup \ u][u]+d(v, u)\ |\ u \notin S\} dp[V][0]=0dp[S][v]=min{dp[S  u][u]+d(v,u)  u/S}
这个递推式的下标有一个不是整数,而是一个集合,但是我们可以把它编码成一个整数,把每一个元素是否在集合内对应到一个二进制位里,从而把状态压缩成一个整数,方便计算和维护。

int dp[1<<MAXN][MAXN]
void DP()
{
	for(int S=0;S<(1<<n);S++)
	{
		fill(dp[S], dp[S]+n, INF);
	}
	dp[(1<<n)-1][1] = 0;
	for(int S=(1<<n)-1;S>=0;S--)      //枚举状态 
	{
		for(int v=1;v<=n;v++)
		{
			for(int u=1;u<=n;u++)
			{
				if(!((S>>u)&1))
				    dp[S][v] = min(dp[S][v], dp[S|(1<<u)][u]+d[v][u]);
			}
		}
	}
	return dp[0][1];
}

这样就可以在 O ( 2 n × n 2 ) O(2^n \times n^2) O(2n×n2) 的时间内完成计算。虽然还是很高,但比起阶乘还是好很多。这样针对集合的DP一般叫状态压缩DP。

例题

ACwing 91. 最短Hamilton路径 .

洛谷P1879 [USACO06NOV]Corn Fields G.

AtCoder Beginner Contest 190 E - Magical Ornament.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值