我们引用国家队2008年陈丹琦的大作——《基于连通性状态压缩的动态规划问题》,上面对于插头、轮廓线的概念有详细的解释,不再赘述。

我们使用一个三维数组,前两维表示所在的格子,后一维表示轮廓线的状况,值为方案数。

在每一行开始前,我们需要把上一行最右的轮廓线转换为这一行最左的轮廓线,因此执行一次左移操作(实际上轮廓线是进行了向右的一次滑动)

然后枚举所在单元格对每个轮廓线的影响 在论文中我们可以发现轮廓线总是包围一个格子的上部分和左部分 我们认为如果有通路与轮廓线重合则为1否则为0

因此很容易想象出来(当然也可以看论文)各个状态之间的转移关系 对于可通行的格子 分部分覆盖和全部覆盖以及全部不覆盖的情况讨论

对不可通行的格子必须将不可能的覆盖方案置为0 到最后的结果就是所求的方案了即dp[m][n][0]

感谢DK大牛的指导 本人5天来的苦思冥想终于得到了成果 1693 0ms 排行统计第一....

以下为本人代码:

#include <iostream>
using namespace std;
typedef __int64 LL;
LL dp[12][12][1<<12];
long hash[12][12];

int main()
{
    long T;
    long b=1;
    scanf("%ld",&T);
    while (T--)
    {
        long i,j,k,m,n;
        scanf("%ld %ld",&m,&n);
        for (i=1;i<=m;++i)
        {
            for (j=1;j<=n;++j)
            {
                scanf("%ld",&hash[i][j]);
            }
        }

dp[0][n][0]=1;

for (i=1;i<=m;++i)
        {
            long len=1<<n;
            for (j=0;j<len;++j)
            {
                dp[i][0][j<<1]=dp[i-1][n][j];
            }

for (j=1;j<=n;++j)
            {
                len=(1<<n<<1);
                for(k=0;k<len;++k)
                {
                    long p=1<<j;
                    long q=p>>1;
                    
                    bool x=p&k;
                    bool y=q&k;

if (hash[i][j])
                    {
                        dp[i][j][k]=dp[i][j-1][k^p^q];
                        if (x!=y)
                        {
                            dp[i][j][k]+=dp[i][j-1][k];
                        }
                    }
                    else
                    {
                        if (x==0&&y==0)
                        {
                            dp[i][j][k]=dp[i][j-1][k];
                        }
                        else
                        {
                            dp[i][j][k]=0;
                        }
                    }
                }
            }
        }
        printf("Case %ld: There are %I64d ways to eat the trees.\n",b++,dp[m][n][0]);

}
    return 0;
}

以下为DK大人的sample代码,我加上了注释:

#include<iostream>
using namespace std;
int mat[100][100];
__int64 dp[12][12][1<<12];
int main()
{
    // freopen("1.txt","r",stdin);
    int zu;
    int g=1;
    scanf("%d",&zu);
    while(zu--)
    {
        int m,n;
        scanf("%d%d",&m,&n);
        int i,j,k;
        for(i=1;i<=m;i++)
            for(j=1;j<=n;j++)
                scanf("%d",&mat[i][j]);
            //memset(dp,0,sizeof(dp));
            dp[0][n][0]=1;
            for(i=1;i<=m;i++)
            {
                for(j=0;j<(1<<n);j++)
                    dp[i][0][j<<1]=dp[i-1][n][j];
                //把最右边的去掉 把所有的状态拉到下一行并进行合理的改变(注意最左边的是低位所代表的数) 
                //上一行最右边的边格一定不与轮廓线重合 下一行最左边的边格也一定不与轮廓线重合 
                //所以进行的是上一行所有状态(也就是轮廓线)向右的一次滑动
                    for(j=1;j<=n;j++)//枚举决策线的拐向
                    {
                        for(k=0;k<(1<<n<<1);k++)//枚举轮廓线
                        {
                            int p=1<<j;//第j个轮廓段(上)
                            int q=p>>1;//第j-1个轮廓段(左)
                            bool x=k&p;//左轮廓是否与通路相交
                            bool y=k&q;//上轮廓是否与通路相交
                            
                            //判断轮廓线在[i,j]为拐向时的分布 每个格子有1<<n<<1种 多阶段决策
                            
                            if(mat[i][j])//如果该单元可以通行
                            {
                                dp[i][j][k]=dp[i][j-1][k^p^q];//必然有一个通路连接上一个格的通路
                                if(x!=y)
                                    dp[i][j][k]+=dp[i][j-1][k];//有一处新覆盖则有另外的一种情况
                            }
                            else//否则为障碍格子
                            {
                                if(x==0&&y==0)//通路与轮廓线不相交
                                    dp[i][j][k]=dp[i][j-1][k];//直接转移
                                else
                                    dp[i][j][k]=0;//通路与轮廓线相交的方案一定为0
                            }
                        }
                    }
            }
            printf("Case %d: There are %I64d ways to eat the trees.\n",g++,dp[m][n][0]);
    }
    return 0;

转载于:https://www.cnblogs.com/zhuangli/archive/2008/09/04/1283753.html

HDU 1693(状态压缩 插头DP)相关推荐

  1. hdu 5067(状态压缩dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5067 解题思路:这道题开始想复杂了,想用bfs去求出最短距离,其实没必要,因为题目中没有阻碍关系,所以 ...

  2. HDU 1565 状态压缩

    题意: 你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大.(n <= 20 ...

  3. 洛谷 P-4045 密码(AC自动机+状态压缩+数位DP+乱搞)

    洛谷 P-4045 密码 记AC的第一道黑题! 题意:已知一段密码包含了一些字符串,然后求满足条件的密码有多少个,数量小于42时还得全部输出 思路: 一开始WA了两个点,不知道WA的什么,索性把读入的 ...

  4. TYVJ 2054 [Nescafé29]四叶草魔杖 最小生成树 状态压缩/背包DP

    $ \rightarrow $ 戳我进TYVJ原题 [Nescafé29]四叶草魔杖 题目限制 时间限制 内存限制 评测方式 题目来源 1000ms 131072KiB 标准比较器 Local 题目背 ...

  5. hdu 5713(状态压缩DP)

    要进行两次dp, 第一个,dp[i],1<=i<=(1<<n) 其中用i的二进制形式表示已选择的点. dp[i] 用来保存i中的点构成一个连通块,边集多少种可能. 转移方程: ...

  6. 洛谷 P2051 [AHOI2009]中国象棋 状态压缩思想DP

    P2051 [AHOI2009]中国象棋 题意: 给定一个n*m的空棋盘,问合法放置任意多个炮有多少种情况.合法放置的意思是棋子炮不会相互打到. 思路: 这道题我们可以发现因为炮是隔一个棋子可以打出去 ...

  7. hdu 5434(状态压缩+矩阵优化)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5434 官方题解: 这个题用状态转移得到矩阵,再矩阵快速幂就可以了. 合体象的攻击范围是变少了的,我们可 ...

  8. ZOJ 3502 Contest 状态压缩 概率 DP

    链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3502 1 #include <iostream> 2 # ...

  9. Acwing291. 蒙德里安的梦想:状态压缩dp

    文章目录 题目分析 状态表示 状态转移 时间复杂度 题目链接 题目分析 题意重述:给定n*m的方格,看能分成多少个1 *2的小方块. 题目分析: 摆放方块的时候,先放横着的,再放竖着的.总方案数等于只 ...

最新文章

  1. 反转链表JAVA算法_链表反转算法
  2. GO语言中json与map的转换
  3. Python3网络爬虫快速入门实战解析(一小时入门 Python 3 网络爬虫)
  4. Python---堆里有16颗豆子,有两个玩家依次取豆
  5. python面向对象作业_python面向对象编程作业
  6. idea怎么更改推到github的路径_IDEA 拉取、上传、更新 项目到 Gitee+GitHub_超详细超简单版...
  7. char赋值字符串常量和数值的区别
  8. Flink从入门到入土
  9. Spring Framework--Data Access(1)--Transaction Management(2) - 声明式事务管理
  10. PL/SQL Developer 8注册码
  11. js使用闭包循环为a标签正确添加事件
  12. 最具有中国特色的脑筋急转弯
  13. 【python 作日期的折线图和柱状图组合图】
  14. 机器学习sklearn----支持向量机SVC模型评估指标
  15. SpringBoot分布式项目实现Session共享
  16. 麻辣烫有几种类型?不同种麻辣烫怎么做
  17. 香港等海外公司如何开通认证微信公众号?
  18. 加强【圣域2】各个技能的打击感-华丽的击飞效果
  19. Linux Shell 并行
  20. scite可以编程c语言不,SciTE中文使用步骤.doc

热门文章

  1. 求多项式解(三种方法MATLAB)
  2. sublime Text3插入参考文献问题
  3. django查询表记录的十三种方法
  4. CF572_Div2_D2
  5. TCP/IP 笔记 - TCP连接管理
  6. [hdu] 5696 区间的价值 || 序列分治
  7. 如何阅读学术论文、聆听学术报告 —— 叶志明
  8. Swift - 移除页面视图上的所有元素
  9. 亿能 性能测试课程 2013年度 公开课 深圳站
  10. C语言a+++b的问题