插头dp

关于插头dp的一点理解

如果是自学的话,有福了,我懵逼了好几天
但可以看看这个PPT
在看看代码应该可以加深理解。练习题一,我写了一点注释,希望有帮助

前导算法
状态压缩dp
位运算

算法干嘛
求哈密顿回路 条数

算法思路
定义了两个东西 (PPT中图文相结合)

1.插头:一个格子某个方向的插头存在表示这个格子在这个方向与相邻格子相连.
2.轮廓线:已决策格子和未决策格子的分界线

我们用状态压缩的方法 表示一排插头的状态

状态转移和PPT略有不同,我们采用2进制,方便位运算。共有三类

1.右下没有插头:如果经过这个格子,左上插头 
2.右下有两个插头:左上不能有插头了
3.右下有一个插头:左上还应该有一个插头

算法阶段
第1步 整体的初始化
第2步 枚举行(调用3 4 5)
第3步 对本行初始化(传承 本行 上一行)
第4步 枚举元素 (调用 5)
第5步 枚举状态 ,状态转移

个人感觉
好牛叉的算法,针对性似乎很强

模板

memset(dp,0,sizeof(dp));
dp[0][m][0]=1;
for(int i=1;i<=n;i++){  //枚举每一行 
    for(int k=0;k<(1<<m);k++){      //初始化本行第零个元素 即加入第一个向右插头 
        dp[i][0][k<<1]=dp[i-1][m][k];
    }
    for(int j=1;j<=m;j++){ //枚举本行的每个元素 
        int r=1<<j;     // 用于检查向右的插头 
        int d=1<<(j-1); // 用于检查向下的插头
        for(int k=0;k<(1<<m+1);k++){ //枚举可以的状态 
            if(mp[i][j]){ //有树要吃 
                if((r&k)&&(d&k)){   //有两个插头 
                    dp[i][j][k]=dp[i][j-1][k-r-d]; // 没有插头传递过来 
                }
                else if((r&k)==0&&(d&k)==0){ // 没有插头 
                    dp[i][j][k]=dp[i][j-1][k+r+d]; //说明 有两个插头传递过来 
                }
                else{ //有一个插头 
                    dp[i][j][k]=dp[i][j-1][k^r^d]+dp[i][j-1][k]; // 传递一个插头 
                }
            }
            else{//没有树 
                if((r&k)==0&&(d&k)==0){  //没有插头 
                    dp[i][j][k]=dp[i][j-1][k]; //无需传递插头 
                }
                else{
                    dp[i][j][k]=0;  // 不可能有插头 
                }
            }
        } 
    }
}

这些题大家可以练习(遇到补充)

1.HDU - 1693 Eat the Trees
求哈密顿回路数,
我写的题解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值