好学易懂 从零开始的插头DP(一)

本文以初学者视角介绍插头DP的基础概念与应用,通过实例解析插头DP的原理及实现方法,适合状态压缩DP初学者。

好学易懂 从零开始的插头DP(一)

写在前面

这是一篇,以蒟蒻视角展开的梳理总结。更改了一些顺序,变化了一些细节。方便蒟蒻学习理解(起码本蒟蒻是这样)。大佬们可以直接看其它大佬的博客,可以学的更快。

你必须要学会的前置知识:状态压缩DP
学不会依旧可以读,但是推荐学的前置知识:哈希

论文贡前面,建议读完博客再看。
《基于连通性状态压缩的动态规划问题》

什么是插头DP

很显然,是一个关于插头的动态规划。那么,什么是插头呢?

如图我们在一个方格内,关于格点画一条闭合回路。

对于每一个方格,内部,有六种情况
在这里插入图片描述
不难发现,对于回路里的任何一个方格,四条边中,有且仅有两个与表示路径的蓝色线相交。这也很好理解,进一次,出一次,C(4,2)=6。
我们现在把格子里的蓝色线条,变成从格子中心指向外边的→。

这个箭头,也就是所谓的插头。

例题

我们结合一个例题来看,这个题目是洛谷模板题的弱化版,很多博客放在了模板题后的第一题,结合个人经历我觉得它比模板题更适合作第一题。
题目链接:HDU1693 or 洛谷P5074
题目大意:给出n*m的方格,有些格子不能铺线,其它格子必须铺,可以形成多个闭合回路。问有多少种铺法?(1<=n,m<=12)

那么,把回路模型变成插头模型有什么好处或者性质呢?
1:首先,我们可以发现,如果一个格子上方的格子有下插头,那这个格子一定有上插头。其它方向类似。
2:按1的方法设置插头,最后一定会构成回路。
3:一个格子的合理取法合且仅合相邻的格子有关。

观察下第三点,它其实代表了无后效性。假设我们从上到下,从左到右的处理每一个格子,那么我们只需要记录部分格子的状态即可,再往上的格子具体状态不用知道。
在这里插入图片描述

如上图,对于当前格子,我们只需要知道红色的这些格子就行了,再上面的格子具体的取法,已经不会对下面任何未处理的格子产生影响。

已经掌握了状态压缩的你,一定能轻松的算出状态总数,每个格子6种,维护n个格子。总共 6 n 6^n 6n种状态,好的,完蛋,只有2e9个状态。
在这里插入图片描述
别急,我们真的需要2e9个状态嘛?这些格子里,指向彼此和已经处理过的格子的插头,显然是废物信息。我们实际上只需要知道这些插头嘛:
在这里插入图片描述
蓝色的是其它格子需要用到的,黄色的是当前格子需要用到的。我们叫红色的这个线为轮廓线。我们只需要知道这轮廓线上m+1个箭头是否存在就可以了。总共 2 m ∗ 2 2^m*2 2m2个状态。再乘上n和m,时空复杂度都绰绰有余。
那么,怎么实现呢?我们要解决两个问题。

1:已知这些插头的情况下,这个方格该如何填。
2:填完这个方格后,如何得到下一个方格所需要的插头状态,更特殊的,如何从上一行行末,变到下一行行初。

这两个问题,其实都不是很难,稍微思考下,都可以独立解答,建议思考后再往下看。图片挡下文大法。
在这里插入图片描述
问题1:
0:若这个格子不能走,则不能存在左侧和上方插头。

1:如果当前格子存在左侧插头和上方插头,那么只有一种合理填法。
在这里插入图片描述
2:如果仅存在左侧插头,那么有两种合理填法。

在这里插入图片描述
3:如果仅存在上方插头,那和上一种类似,也是两种填法。
在这里插入图片描述
在这里插入图片描述
4:如果都不存在呢?只有一种填法
在这里插入图片描述
问题2:
解答了问题1,显然我们也得到了问题2的解答,毕竟我们填出了这个格子,自然知道插头分布。唯一特殊的是上一行末到这一行头的处理。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值