【Codeforces 111C】Petya and Spiders

Codeforces 111 C

题意:给\(n\times m\)的网格,每个点上有一个蜘蛛,每个蜘蛛可以向上、下、左、右走一步或者不动,问最多能存在多少没有蜘蛛的点。

思路1:

首先因为\(n\)\(m\)中小的那个不可能超过\(6\),所以钦定\(m < n\)(因为如果\(n\)\(m\)互换不影响答案)。

然后就可以考虑状压\(dp\)了。

首先我们看\((x,y)\)这个点上面可爱的小蜘蛛的去向。它可能会往上走,到\((x-1,y)\);也可能向下走,到\((x+1,y)\);也可能向左右走;所以就会发现在不断向下一个点移动的过程中,对于\((x,y)\)有影响的是从\((x-1,y)\)\((x+1,y)\)\(2\times m+1\)个点。所以\(dp\)状态和转移方程都可以求出辣:\(dp(x,y,mask)\)表示到了\((x,y)\)这个点,\(mask\)表示从\((x-1,y)\)\((x+1,y)\)的点是否是蜘蛛集合点。

转移方程和\((x,y)​\)上的蜘蛛往哪个方向去走有关,或者它停在原地,它去的那个点必须是蜘蛛集合点,如果原来不是,那么答案必须加1。然后转移到下一个点即可。

思路2:

首先还是钦定\(m < n\)

然后还是考虑状压\(dp\),其状态为\(dp(x,mask)\)。表示第\(x\)行时的状态。

这里\(mask\)保存的是当前行和上一行的所有的蜘蛛是否已经有地方去,然后转移的时候用\(dfs\)枚举一行中哪些点作为集合点(这里需要枚举所有集合点的集合),同时将其四周的点的状态赋为有地方去,然后让当前行的上一行不要有没地方去的点,继续考虑下一行的\(dp\)

思路3:

钦定\(m < n​\),考虑状压\(dp​\),其状态为\(dp(x,mask)​\)

这里\(mask\)保存的是当前行与上一行的集合点集,\(dp\)的值是考虑最多的空闲点的个数。

转移的时候枚举这一行新的集合点集以及下一行的集合点集,然后判断是否有当前行原来是集合点而现在不是的,有没有当前行没地方去的点,如果都没有就可以进入下一行的\(dp\)

总结:

这3种思路较快的是思路1、2,然后较慢的是思路3,因为思路1的时间复杂度是\(O(n\times m\times 2^{2\times m+1})\),思路2的复杂度是\(O(n\times2^{3\times m})\),思路3的复杂度是\(O(n\times2^{4\times m})\)

由此可见,状压\(dp\)的状态选择方面,对于复杂度是有非常大的影响的。

2019.03.03补充:
思路:我们考虑状压\(dp\)\(dp(i,mask0,mask1)\)表示现在我们到了第\(i\)行,第\(i-1\)行的点中\(mask0\)内的的都被十字覆盖过了,第\(i\)行的点中\(mask1\)内的点都被十字覆盖过了,最少的十字数量。

现在枚举以第\(i\)行为中心的十字有哪些,存在\(mask2\)中。然后必须的是第\(i\)行的十字必须将\(mask0\)中可能有的一些空缺填满,然后并且会将\(mask1\)中的\(mask2\)中的点及其左右的点覆盖。这里可以用一种很简单的方式来表示\(mask2\)中的点及其左右:\(mask2|mask2<<1|mask2>>1​\)

然后转移一下就很简单了。

猜你喜欢

转载自www.cnblogs.com/denverjin/p/10468424.html