思想来自:http://blog.pureisle.net/archives/475.html

主要思想是用1和0来表示是否被填,然后根据两行之间的状态关系来构建DP方程。

1.首先初始化第一行 计算第一行可以被横着填的方案数。此时cnt是1 所以其实合法的dp[1][j]都是1

2.然后开始构建第二行至最后一行

  构建每行时,枚举上一行的可行状态,cnt += 达到该状态的方法数,从而计算dp值。

  对上一行的该状态进行取反操作,得到上一行是0的位置,把它们变成1,模拟竖着填。

  然后和全集按位与操作,然后开始构建这一行。

3.注意 要尽量让列的数目变小 因为循环的次数里  H*2^W 让W小比较好。

看着多是因为注释比较多,其实这个方法的代码量极少。

#include <iostream>
#include <cstring>
using namespace std;int W,H;
unsigned long long cnt=1;//用于每次的叠加
unsigned long long dp[30][1<<12];
//dp[i][j] 表示达到第i行的 j状态有多少种方法
//最终答案就达到最后一行全部填满的方法 所以就是 dp[H][(1<<W)-1]void build_line(int line, int from ,int cur ){//line是当前构建的行的行号//from是正在处理状态//cur是当前处理的位置if(cur == W){//一行处理结束了 注意: cur是从0开始到W-1的dp[line][from] += cnt;return;}//保持状态不变 即不去试图填了 向后构建 build_line(line,from,cur+1);//在from的状态基础上继续试图填两个连续横着的空//判断from里是否可以横着填两个if(cur <= W-2 //要保证可以填下 W-2 和 W-1这两个空and !( from & (1<<cur)     )  //保证正在处理的位置和它的下一个位置没有被填and !( from & (1<<(cur+1)) )  //
    ){//横着连续填两个空int next = from | (1<<cur) | (1<<(cur+1)); build_line(line,next,cur+2);//继续构建
    }return;
}int main(int argc, char const *argv[])
{while(1){cin>>W>>H;if(W==0 and H==0)break;if(W > H){//让列数尽量小 优化效率因为W要作为指数int t; t = W; W = H; H = t;}//如果是奇数 直接输出0 然后判断下一状态if( W*H % 2 ==1){cout<<0<<endl;continue;} //清空数组memset(dp,0,sizeof(dp));cnt = 1;//重置为1 build_line(1,0,0);//构建第一行 //从第二行开始枚举上一行的所有状态 构建本行for (int i = 2; i <= H; ++i) //i是行
           {for (int j = 0; j < (1<<W); ++j)//j是枚举出来的i-1行的状态数
               {if(dp[i-1][j] > 0){//如果可以达到上一行的j状态cnt = dp[i-1][j];}else//无效状态 直接返回continue;//取反j 再进行按位与运算 从而求得 可以竖着填的情况build_line(i,(~j) & ((1<<W)-1) ,0);}}//输出结果cout<<dp[H][((1<<W)-1)]<<endl;}return 0;
}

转载于:https://www.cnblogs.com/yuchenlin/p/sjtu_oj_1383.html

【算法学习笔记】67.状态压缩 DP SJTU OJ 1383 畅畅的牙签袋相关推荐

  1. 【算法学习笔记】43.动态规划 逆向思维 SJTU OJ 1012 增长率问题

    1012. 增长率问题 Description 有一个数列,它是由自然数组成的,并且严格单调上升.最小的数不小于S,最大的不超过T.现在知道这个数列有一个性质:后一个数相对于前一个数的增长率总是百分比 ...

  2. 【算法学习笔记】65. 双向扫描 SJTU OJ 1382 畅畅的牙签盒

    http://acm.sjtu.edu.cn/OnlineJudge/problem/1382 注意到 排序之后 i从前向后扫描时,cur恰好是从后向前的,所以即使是双重循环,也是O(n)的算法. # ...

  3. 【算法学习笔记】64. 枚举法 SJTU OJ 1381 畅畅的牙签

    枚举法就好了,推理很麻烦,感觉也做不出来. 创造一个结构体,一个是真实的数,一个是花费的牙签数. 构建一位数,两位数,三位数即可. #include <iostream> #include ...

  4. 【算法学习笔记】75. 动态规划 棋盘型 期望计算 1390 畅畅的牙签盒(改)

    一开始用了模拟的方法,DFS来搜索,但是因为当n很大的时候有很多的重复计算,因为会踏过重复的点进行重复的操作,而且不能不走这些重复的路径,因为没有存储结果,最后只过了三个点. 考虑到重复的路径,所以想 ...

  5. 状态压缩dp学习小记part2

    继续学习状态压缩的相关知识. 本来准备继续按照上篇博文里提到的那篇论文继续学习,但被矩形完全覆盖虐了回来,决定先做些其他的题增进理解之后再回来做. Zoj 3471 Most Powerful 题目链 ...

  6. 《算法竞赛进阶指南》打卡-基本算法-AcWing 91. 最短Hamilton路径:位运算、状态压缩dp、dp

    文章目录 题目解答 题目链接 题目解答 分析: 状态压缩dp是用二进制数来表示状态. 数据范围n = 20, 那么状态总量就是2202^{20}220个状态. 可以按照以下思路去思考: 哪些点被用过 ...

  7. 状态压缩DP AcWing算法提高课 (详解)

    基础课的状态压缩点这里 基础课中 蒙德里安的梦想 属于 棋盘式状态压缩dp,最短Hamilton路径 属于 集合状态压缩dp 1064. 小国王(棋盘式/基于连通性) 这种棋盘放置类问题,在没有事先知 ...

  8. 0x56. 动态规划 - 状态压缩DP(习题详解 × 7)

    目录 Problem A. 最短Hamilton路径 ProblemB. 蒙德里安的梦想 Problem C. Corn Fields Problem D. 小国王 Problem E. 炮兵阵地 P ...

  9. 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列

    (为什么都更了这么多篇笔记了,这时候才讲这么基础的内容呢?因为我本来以为LCS这种简单的DP不用讲的,结果CF不久前考了LCS的变式,然后我发现由于自己对LCS一点都不熟,居然写不出来 ,于是决定还是 ...

最新文章

  1. android面试题总结加强版
  2. 60.Java 代码编译和执行的整个过程
  3. hdu6356-Glad You Came【RMQ】
  4. oracle10g静默升级,Linux下静默安装,升级和删除Oracle10g客户端
  5. 七、【应用的主要框架】
  6. java sqlserver数据库连接_JAVA连接SQLserver数据库
  7. 客户端发现响应内容类型为“text/html”,但应该是“text/xml”
  8. matlab中gain是什么,PID调理中的GAIN是啥意思?
  9. 国内首款红外测温5G手机;华为5G汽车模组正式商用;台湾发放首张5G牌照
  10. Android平板/手机,使用qq视频通话图像旋转90度
  11. 【BLENDER】-渲染 背景设置
  12. L2-3 清点代码库 (25 分)(C/C++)
  13. 关于Java中的锁,看这一篇就够了(总结篇)
  14. torch.utils.data.DataLoader()的使用
  15. 微信小程序电商实战—环境搭建篇
  16. matlab(二)统计图
  17. neo4j-OGM 动态cypher java查询
  18. C++内存管理:内存池实现
  19. 刘强东继续动刀高管!多名VP被换,年底末位10%淘汰...
  20. 2.Latex安装和TeXworks Editor基础

热门文章

  1. 一加手机可以刷鸿蒙系统吗,朋友想把1+手机安装鸿蒙系统,老板收费350,大家千万别被骗了!...
  2. C语言常用语句之-循环语句
  3. 服务器重装系统鼠标没反应,重装系统鼠标键盘不能用怎么解决-重装系统鼠标键盘失灵的解决方法 - 河东软件园...
  4. 1905 统计子岛屿
  5. 什么是基于模型的测试?
  6. 超唯美海洋夕阳日落网站维护HTML源码
  7. 《信息物理融合系统(CPS)设计、建模与仿真——基于 Ptolemy II 平台》——1.8 域和指示器概述...
  8. Asterisk manager API(AMI)文档(中文版)
  9. 中国不是没有根服务器吗?《流浪地球2》的根服务器怎么在北京?
  10. 多线程并发中什么是竞争条件?