hiho_1048_状态压缩2
题目大意
用1x2的单元拼接出 NxM的矩形,单元可以横放或者纵放,N < 1000, M <= 5. 求不同的拼接方案总数。
分析
计算机解决问题的基本思路:搜索状态空间。如果采用dfs进行搜索,则可以将当前搜索的位置(i, j)作为状态,而不保存棋盘的占用情况,每次扩展时进行判断是否可行。这样可以得到最后的结果,但当然会超时。
(1) 参考hiho_1048中的提示,可以知道在搜索的时候按照固定的顺序可以大幅度剪枝(通过将无序的搜索变成有序的搜索来实现)。然后可以对中间结果进行保存,即记忆化搜索。状态dp[i][j][s1][s2] 表示求第i行,第j列位置开始扩展,且第i行的占用状态为s1, 第i+1行的占用状态为s2 时,填满剩余的空格的方案总数。
(2)将记忆化搜索直接使用动态规划来实现,状态 dp2[i][k1][k2] 表示前i-1行都已经填满了,此时第i行的占用情况的二进制表示转换为十进制为 k1,第i+1行的占用情况的二进制表示转换为十进制为 k2,达到此时棋盘占用情况的摆放方案总数。
这样,可以进行状态转移时,枚举第i行的占用情况k1,和第i+1行的占用情况k2,看是否可以进行扩展,blabla...
实现
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define BIT(i, j) (i & (1 << (j - 1)))
const int mod = ;
int dp[][][][]; /*记忆化搜索
n,m为边界n行,m列。
求第i行,第j列位置开始扩展,且第i行的占用状态为s1, 第i+1行的占用状态为s2 时,填满剩余的空格的方案总数
*/
int dfs(int n, int m, int i, int j, int s1, int s2){
if (dp[i][j][s1][s2] != -)
return dp[i][j][s1][s2];
int result = ;
//边界!! 无法继续扩展时,取值为1,表示所有扩展到此的合理情况的初始均为1
if (i > n || j > m || s1 >= ( << m) || s2 >= ( << m))
return ;
//如果第i行位置j(从右向左)被占用,且j < m,向左扩展
if (BIT(s1, j) && j < m)
result = dfs(n, m, i, j + , s1, s2);
//如果第i行位置j(从右向左)被占用,且j = m,向下一行扩展
else if (BIT(s1, j) && j == m)
result = dfs(n, m, i + , , s2, );
//如果第i行位置j没有被占用,且无法向左或者向下扩展
else if (BIT(s1, j) == && (j == m || BIT(s1, j + )) && (i == n || BIT(s2, j)))
result = ;
//如果第i行位置j没有被占用,且只能向左扩展
else if (BIT(s1, j) == && j < m && BIT(s1, j + ) == && (i == n || BIT(s2, j)))
result = dfs(n, m, i, j, s1 | ( << (j - )) | ( << j), s2);
//如果第i行位置j没有被占用,且只能向下扩展
else if (BIT(s1, j) == && (j == m || BIT(s1, j + )) && (i < n && BIT(s2, j) == ))
result = dfs(n, m, i, j, s1 | ( << (j - )), s2 | ( << (j - )));
//如果第i行位置j没有被占用,且可以向左或向下扩展
else if (BIT(s1, j) == && j < m && BIT(s1, j + ) == && i < n && (BIT(s2, j) == ))
result = dfs(n, m, i, j, s1 | ( << (j - )) | ( << j), s2) +
dfs(n, m, i, j, s1 | ( << (j - )), s2 | ( << (j - )));
//记忆化保存
return dp[i][j][s1][s2] = result % mod;
} //动归数组, dp2[i][k1][k2] 表示前i-1行都已经填满了,此时第i行的占用情况的二进制表示转换为十进制为 k1,
// 第i+1行的占用情况的二进制表示转换为十进制为 k2
int dp2[][][];
int main(){
int n, m;
scanf("%d %d", &n, &m);
/*
记忆化搜索
memset(dp, -1, sizeof(dp));
int result = dfs(n, m, 1, 1, 0, 0);
printf("%d\n", result);
*/ //动态规划
memset(dp2, , sizeof(dp2));
//初始状态,第1行未被占用,只有1种可能。
dp2[][][] = ;
int mx = << m;
for (int i = ; i <= n; i++){
/*
下面的 j (第i行从右到左的每个位置)循环放在 k1(第i行当前的bit状态) 之前是为了去除重复! 因为我们总是按照顺序从上到下,从右到左枚举当前可以放置方块的位置点,
在循环到每个(i, j)点,都看当前的哪些k1状态可以在次扩展
*/
for (int j = ; j <= m; j++){
//枚举第i行的所有情况(占用情况的二进制表示转换为十进制)
for (int k1 = ; k1 < mx; k1++){
//如果第i行的第j个位置(从右向左)为0,则可以从这里开始扩展
if ((k1 & ( << (j - ))) == ){
//看是否可以横向扩展
if (j < m && ( (( << j) & k1) == )){
//状态转移
for (int k2 = ; k2 < mx; k2++){
dp2[i][k1 | ( << j) | ( << (j - ))][k2] =
(dp2[i][k1 | ( << j) | ( << (j - ))][k2] + dp2[i][k1][k2]) % mod;
}
}
if (i < n) //看是否可以纵向扩展
//当前的第i+1行的占用情况
for (int k2 = ; k2 < mx; k2++){
//如果第i+1行的第j个位置(从右向左)为0,则可以纵向扩展
if ((( << (j-)) & k2) == )
//状态转移
dp2[i][k1 | ( << (j - ))][k2 | ( << (j - ))] =
(dp2[i][k1 | ( << (j - ))][k2 | ( << (j - ))] + dp2[i][k1][k2]) % mod;
}
}
}
}
//当第i行全部被占用满时,可以将第i+1行的状态 转移到 i+1行的当前行
for (int k = ; k < mx; k++){
dp2[i + ][k][] = dp2[i][mx - ][k];
}
}
//最后的结果是n行全部占满,此时第n行为 mx-1, 第n+1行为0
printf("%d\n", dp2[n][mx-][]);
return ;
}
hiho_1048_状态压缩2的更多相关文章
- POJ 3254. Corn Fields 状态压缩DP (入门级)
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9806 Accepted: 5185 Descr ...
- HDU 3605:Escape(最大流+状态压缩)
http://acm.hdu.edu.cn/showproblem.php?pid=3605 题意:有n个人要去到m个星球上,这n个人每个人对m个星球有一个选择,即愿不愿意去,"Y" ...
- [HDU 4336] Card Collector (状态压缩概率dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4336 题目大意:有n种卡片,需要吃零食收集,打开零食,出现第i种卡片的概率是p[i],也有可能不出现卡 ...
- HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)
题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由 ...
- codeforces B - Preparing Olympiad(dfs或者状态压缩枚举)
B. Preparing Olympiad You have n problems. You have estimated the difficulty of the i-th one as inte ...
- NOIP2005过河[DP 状态压缩]
题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数 ...
- vijos1426兴奋剂检查(多维费用的背包问题+状态压缩+hash)
背景 北京奥运会开幕了,这是中国人的骄傲和自豪,中国健儿在运动场上已经创造了一个又一个辉煌,super pig也不例外……………… 描述 虽然兴奋剂是奥运会及其他重要比赛的禁药,是禁止服用的.但是运动 ...
- hoj2662 状态压缩dp
Pieces Assignment My Tags (Edit) Source : zhouguyue Time limit : 1 sec Memory limit : 64 M S ...
- poj3254 状态压缩dp
题意:给出一个n行m列的草地,1表示肥沃,0表示贫瘠,现在要把一些牛放在肥沃的草地上,但是要求所有牛不能相邻,问你有多少种放法. 分析:假如我们知道第 i-1 行的所有的可以放的情况,那么对于 ...
随机推荐
- HDU(4734),数位DP
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=4734 F(x) Time Limit: 1000/500 MS (Java/Others) ...
- NYOJ(21),BFS,三个水杯
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=21 BFS判环,vis标记状态即可. #include <stdio.h> # ...
- 如何让其他计算机访问我的计算机上数据库mysql
第一种:能ping通,说明你们在同一个网络中,可以直接访问.你只要在你的登录用户中的帐号加上可外部访问就可以了...也就是授权.比如你的帐号是root 你可以进入mysql后, 你可以看到,每个帐 ...
- xcodeheader search 配置
一般我们在xcode里面配置包含工程目录下头文件的时候,都要关联着相对路径和绝对路径,如果只是自己用这个项目,用绝对路径的问题不大,但是如果你把工程发给别人,别人就要在改这个绝对路径,这时候绝对路径的 ...
- 第五课 SharedPrefereneces
SharedPreferences总结: 一.SharedPreferences特点 1.本质是基于xml文件储存key-value对数据: 2.SharedPreferences对象本身只能获取数据 ...
- 数据库批量修改表名,增加前缀(SQL server)
exec sp_msforeachtable @command1=' declare @o sysname,@n sysname select @o=''?'' ,@n=stuff(@o,1,7,'' ...
- Mysql ERROR 1064 (42000)
创建了一个表: +-------------+--------------+------+-----+---------+----------------+ | Field | Type | Null ...
- C#打印条码的几种方式
标题虽然是说C#,但是以下介绍的几种方法不是只能在C#中使用,在其它的语言里面也行. 总结一下常见的条码打印方法,其实打条码的方式很多,大概有以下几种: 1.斑马打印软件制作好模板,保存为.prn格式 ...
- POJ 3069 Saruman's Army(萨鲁曼军)
POJ 3069 Saruman's Army(萨鲁曼军) Time Limit: 1000MS Memory Limit: 65536K [Description] [题目描述] Saruman ...
- 微博传播数量和传播深度的预测--基于pyspark和某个回归算法
8-28决定参加一下这个千万条的数据处理任务,因为场景和自己做过的一个回归分析预测差不多,第一天开始在小规模的数据上做准备工作. 第二次大修改版本 date 20160829 星期一¶ 原始数据处理, ...