插头DP讲解+[BZOJ1814]:Ural 1519 Formula 1(插头DP)

1.什么是插头DP?

插头DP是CDQ大佬在2008年的论文中提出的,是基于状压DP的一种更高级的DP多用于处理联通问题路径问题,简单回路问题,多回路问题,广义回路问题,生成树问题)。

插头DP每道题都不一样,且需要进行较为繁琐的分类讨论,所以插头DP十分锻炼思维的严谨性和全面性。


2.插头DP思路

  $\mathcal{A.}$状态确立

    $\alpha.$插头

      插头表示一种联通状态

      在棋盘模型中,一个格子有向某方向的插头,表示这个格子在这个方向与插头那边的格子相连。

      注意:插头并不是说将要去某处的虚拟状态,而是已经到达某处的现实状态

      我们需要考虑的是接下来往哪里走,因为如果有一个插头指向当前格子,说明当前格子已经与插头的来源有联通了。

      有了插头,就方便多啦,我们一般需要的是进行逐格递推,通俗的讲,就是跑一遍。

    $\beta.$轮廓线

      轮廓线就是一条分界线,至于它为什么叫轮廓线,我也不知道,就像CDQ为什么叫CDQ一样,她也不知道,但是她爸妈知道。

      你可以感性的将它理解为是“已经决策了的格子”与“还没有决策的格子”的分界线。

      但是,轮廓线的用途不止如此。

      轮廓线还兼容了存储这条分界线上插头状态的作用。

      需要注意的是,假设一行内有m个格子,那么会有m+1个插头,为什么呢?

      看一下下面的这张图:

      

      显然一行内有4个格子,但是有5个插头,多出来的那一个插头在当前正在决策的那个格子的右侧。

      个人习惯将插头编号为1~m。

      一般数据范围比较小,我们可以用状压来存储,即定义dp[i][j][state]表示当前决策到(i,j)这个点,状态为$state$的方案数(或代价,etc)。

    $\chi.$插头与轮廓线的结合

      插头与轮廓线结合在一起,就会碰撞出一些美丽的火花。

      我们递归的时候就是依据插头的存在性,来求出所有能转移到的合法状态。

      在回路问题中,对于一个状态一个格子恰好有两个插头,一个“进来”,一个“出去”。

  $\mathcal{B}.$记录状态

    下面来介绍三种记录状态的方式:

    $\alpha.$最小表示法

      为了方便,所有有障碍的格子记为0,第一个非障碍的格子以及所有与它相连的格子标记为1,第一个未标记的格子以及与它相邻的格子标记为2……

      重复以上的过程,直到所有的格子都标记完毕。

      举个栗子:

        1,2,5联通,3,6联通,4自己和自己卡在一起,那么其最小表示法即为{1,1,2,3,1,2}。

    $\beta.$括号表示法

      先来看一个性质:假设一条轮廓线上有4个插头a,b,c,d,a与c联通且不与b联通,那么b与d肯定也不联通。

      这个性质很重要,因为它适用于所有的棋盘问题

      

      就像这样,显然如果b与d也相交的话就不可能满足情况了。

      再具体一点:

      

      相信细心的你一定会发现,轮廓先上方的路径都是由若干条互不相交的路径构成的,原因就是再上面那张图。

      每条路径上的两个端点也会恰好对应轮廓线上的两个插头

      有点跑题了,这种“不交叉”很容易让我们联想到括号匹配,左括号为进栈,右括号为出栈,左括号一定与右括号一一对应。

      当然有可能会让你想到卡特兰数,这点很重要,能帮你卡常。

    $\chi.$状态的编码

      利用状压的思想,我们将每行m+1个状态用一个m+1位的k进制数表示,在做题的时候建议将k改为2的n次幂,方便进行为运算,运行速度会有很大的提升(前提空间允许)。

      小技巧:如需大范围修改联通状态,可以选择

猜你喜欢

转载自www.cnblogs.com/wzc521/p/11260885.html