【POJ1739、travel、画圈圈】连通性状态压缩DP

 

其实这所谓连通性状态压缩dp并不麻烦,有模板可循

 

算法流程

1.       预处理出所有有效状态,这个有效状态的定义是所有括号是配对的,即括号序列合法,并给每个状态一个唯一对应的哈希值(3进制),我用0表示无插头,1表示左插头,-1表示右插头

2.       预处理出所有转移,形如g[i,j,k],表示轮廓线的状态为i,转折点为j,第k号转移到哪个状态(编号,不记哈希值)。一般是以下几种转移(但对于每个特定的格子只有两种转移)

0 0 –> 0 0 or 1 -1 空格不管或在空格新建两个插头

0 1 –> 0 1 or 1 0 将一边的插头延续,2个方向均可

0 -1 -> 0 -1 or -1 0将一边的插头延续,2个方向均可

1 0 -> 1 0 or 0 1将一边的插头延续,2个方向均可

-1 0 -> -1 0 or 0 -1将一边的插头延续,2个方向均可

1 -1 -> 0 0 将一个连通块合并,“收圈”

-1 1 -> 0 0 合拢两条挤到一起的“线”

p1

1 1-1 -1 -> 0 01 -1合拢两条挤到一起的“线”

p2

1 1-1 -1 -> 1 -10 0合拢两条挤到一起的“线”

p3

需要注意的是,找某状态对应的编号应用hash,不能裸找,裸找能慢十几倍

注:图片来自盾哥博客

3.       搞完了预处理,dp就容易多了,一般是根据题目看某些特殊的格子只能有特定的转移,讨论一下即可。这里的空间消耗一般会比较大,所以一般得写滚动数组

 

有了这些预处理,dp就方便多了,直接写就可以了

 

【POJ1739】

 

直接用连通性状态压缩dp求哈密尔顿路径有点麻烦,所以可以看成是求从(n,1)->(n,m)再从(n,m)->(n+1,m)->(n+1,1)->(n,1)的一条哈密尔顿环即可

具体的话相当于直接dp,ans=f[n+1,1,第二个有左括号,第m+1有右括号的状态]

 

 

travel

题意:

在N*M的方格上,求(a,b) -> (c,d)的哈密尔顿路径条数

算法:

在上面的基础上加入独立插头

 

4进制表示,论文中没有说,这里补充一下,关于插头的准确定义

独立插头:往上延伸没有回到轮廓线上

左括号:往上延伸并回到轮廓线上,且对应点在这个位置的右边

右括号:与左括号相反

主要有以下几种转移

只有起点和终点允许的:

1.两边都没有插头 -> 往任一方向开一独立插头

2.只有一边有括号 –> 把这个括号消掉,并把这个括号原来对应的括号改成独立插头

3.只有一个独立插头过来 –>消掉这个独立插头

非起点终点或(n,m)允许的:

一边是括号,一边是独立插头 -> 合并这个括号和独立插头,同时把与那个括号配对的括号改成独立插头

(n,m)非起点终点时只有(n,m) 允许的:

合并两个独立插头

 

另外,所有点都不允许合并左右插头

所以这样就可以了

代码:

 

 

ps:加入独立插头后状态数激增。。

 

【画圈圈】

今年集训队的题目,大意就略了吧,ms衡阳八中OJ上有

题目主要就是要确定每个点是圈圈内部还是外部,这里其实只要统计包含它的括号对数即可,基数为内部,偶数为外部

代码:

 

 

这种题目还是挺麻烦的!另外,NOI2010那道神题暂时还没弄懂,以后再说吧

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值