2934. 插头DP

给你一个 \(n \times m\) 的棋盘,有的格子是障碍,问共有多少条回路满足经过每个非障碍格子恰好一次。

image

如图,\(n=m=4\)\((1,1),(1,2)\) 是障碍,共有 \(2\) 条满足要求的回路。

输入格式

第一行包含两个整数 \(n,m\)

接下来 \(n\) 行,每行包含一个长度为 \(m\) 的字符串,字符串中只包含 *.,其中 * 表示障碍格子,. 表示非障碍格子。

输出格式

输出一个整数,表示满足条件的回路数量。

数据范围

\(2 \le n,m \le 12\)

输入样例:

4 4
**..
....
....
....

输出样例:

2

解题思路

插头dp

插头dp 主要用来解决一些网格图上的哈密顿回路方案的相关问题
本题即 插头dp 模板题,即给出一个网格图,并且要求一些格子不能经过,求哈密顿回路的方案数
做法通常是一格一格做,由于是哈密顿回路,即每个格子会有两条出边(即插头),处理当前格子的时候之前,记录上一行边界出边的状态,通常记录这些的状态有两种方法:

  1. 最小表示法:由于上面每一个出边,一定会对应另外一条出边,对于每一对匹配边,用同一个数字表示,不同对匹配边之间用不同的数字表示,最后所有的这样的数字连起来的最小表示法即为该边界的状态
  2. 括号表示法(效率一般更高,因为可以转化为进制之间的运算):从左往右,如果没有当前边界没有出边则用 \(0\) 表示,否则如果该匹配边在左边用 \(1\) 表示,在右边用 \(2\) 表示,最后会形成 \(012\) 这样的数字,但是这样的数字得用四进制表示,原因在于四进制好进行位运算

状态表示:\(f[i][j][s]\) 表示处理到 \((i,j)\) 这个格子时边界状态为 \(s\) 时得方案数

状态计算:
插头dp 的状态转移一般比较复杂,需要分好多情况讨论(这里采用括号表示法):
image
处理到 \((i,j)\) 这个格子的时候,其左边界插头的状态为 \(x\),上边界插头的状态为 \(y\)\(0\leq x,y\leq 2\)

  1. 如果 \((i,j)\) 是障碍物,则要求 \((i,j)\) 上不能出现插头才是合法状态,即 \(x=y=0\),此时状态不变
  2. 如果 \(x=y=0\),即左边界和上边界都没有插头,因为哈密顿回路要求每一个非障碍物的格子都要有两个插头,且这两个插头是连通的,即一定有一个出去然后另外一个回来,更新状态,由定义:\(x\leftarrow 1,y\leftarrow 2\)
  3. \(x=0,y\neq 0\),此时 \(y\) 这个插头有两种选择:向下、向右。向右时当前格子的右边界状态即为 \(y\),下边界状态为 \(0\);向下时下边界状态为 \(y\),右边界状态为 \(0\)
  4. \(x\neq 0,y=0\),同样地,此时 \(x\) 这个插头有两种选择:向下、向右。向右时当前格子的有边界状态为 \(x\),下边界状态为 \(0\);向下时下边界状态为 \(x\),右边界状态为 \(0\)
  5. \(x=y=1\),此时两个插头连通,当前格子的右、下边界状态都为 \(0\),且右边对应的状态需要修改,即此时两个状态 \(x,y\) 都有一个匹配插头,且都在右边,状态都为 \(2\),由于这两个插头已经连通,所以右边之前未匹配的插头开始匹配,即将右边两个匹配的插头的第一个插头状态修改为 \(1\)
  6. \(x=y=2\),同理,此时两个插头连通,当前格子的右、下边界状态都为 \(0\),且左边对应的状态需要修改,即此时两个状态 \(x,y\) 都有一个匹配插头,且都在左边,状态都为 \(1\),由于这两个插头已经连通,所以左边之前未匹配的插头开始匹配,即将右边两个匹配的插头的第二个插头状态修改为 \(2\)
  7. \(x=2,y=1\),此时两个插头连通,当前格子的右、下边界状态都为 \(0\),由于此时两个插头连通,但是对应的匹配的插头正好左边的匹配插头状态为 \(1\),右边的匹配插头状态为 \(2\),所以这时这样的状态不用修改
  8. \(x=1,y=2\),此时两个插头连通,但是对于当前 \(x\) 来说,其对应的匹配插头在右边,对于 \(y\) 来说,其对应的匹配插头在左边,这样两条路径要么相交,要么重合,由于两条路径相交的话就不再是一条哈密顿回路,所以只能重合,而重合说明当前遍历的格子一定得是最后一个合法的格子

设有效状态数量为 \(S\),则:

  • 时间复杂度:\(O(n^3\times S)\)

代码


posted @ 2022-12-13 12:14  zyy2001  阅读(90)  评论(0编辑  收藏  举报