问题描述:

给定m×n个格子,每个格子被染成了黑色或白色。现在要用1×2的砖块覆盖这些格子,要求快于快之间互相不重叠,且覆盖了所有白色的格子(用 . 表示),但不覆盖任意一个黑色的格子(用 x 表示)。求一共有多少种覆盖方法,输出方案数对M取余后的结果。

首先考虑一下枚举所有的解法这一方法。为了不重复统计,我们每次从最左上方的空格处开始放置。对于哪些格子已经被覆盖过了,我们只需要用一个bool数组来维护即可,即:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int n,m,M;
char tu[20][20];
bool used[20][20];
int rec(int i,int j,bool used[20][20])
{
if(j==m)///当前这一行已经走完了
{
return rec(i+1,0,used);
}
if(i==n)///已经把整个图都走完了
{
return 1;
} if(used[i][j]||tu[i][j]=='x')///当这个点已经放过或者说是黑色的,则不需要放置地砖
{
return rec(i,j+1,used);
} int res=0;
used[i][j]=true;///标记这个点已经放过了 ///横着放
if(j+1<m&&!used[i][j+1]&&tu[i][j+1]=='.')///横着放能够放
{
used[i][j+1]=true;///笔记后面那个格子
res+=rec(i,j+1,used);///接着往下找
used[i][j+1]=false;///标记释放
}
///竖着放
if(i+1<n&&!used[i+1][j]&&tu[i+1][j]=='.')///竖着放能够放
{
used[i+1][j]=true;///标记下面那个格子
res+=rec(i ,j+1,used);///刚开始以为这里应该是rec(i,j+1,used),后来发现理解错了,i,j只是表示往后走
used[i+1][j]=false;///标记释放
} used[i][j]=false;///当前格子的标记释放
return res%M;
} void solve()
{
memset(used,0,sizeof(used));
printf("%d\n",rec(0,0,used));
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&M))
{
for(int i=0; i<n; i++)
scanf(" %s",tu[i]);
solve();
}
return 0;
}

这个方法无法在规定的时间内求出答案。而且递归的参数共有n×m×2^nm种可能,也无法使用记忆话搜索。

首先,由于黑色的格子不能被覆盖,因此used里对应的 位置总是false。对于白色的格子,如果要在(i,j)位置上放置砖块,那么由于总是从最左上方可以放的位置开始放,那么对于(i',j')<(i,j)(按字典序比较)的(i',j')总有used[i'][j']=true成立。

此外,由于砖块的大小为1×2,因此对于每一列j'在满足(i',j')>=(i,j)的所有i'中,除了最小的i‘之外,都满足used[i'][j']=false。因此,不确定的只有每一列里还没有查询格子中最上面的一个,共m个。从而把这m个格子通过状态压缩编码进行记忆化搜索,复杂度为(n×m×2^m)。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
using namespace std;
int n,m,M;
char tu[20][20];
//bool used[20][20]; int dp[2][1<<20];
void solve()
{
int *crt=dp[0],*next=dp[1];
crt[0]=1;
for(int i=n-1; i>=0; i--)
{
for(int j=m-1; j>=0; j--)
{
for(int used=0; used<1<<m; used++)
{
///不需要在[i,j]放置砖块
if((used>>j&1)||tu[i][j]=='x')
{
next[used]=crt[used&~(1<<j)];
}
else
{
int res=0;
///横着放
if(j+1<m&&!(used>>(j+1)&1)&& tu[i][j+1]=='.')
{
res+=crt[used|1<<(j+1)];
} ///竖着放
if(i+1<n&&tu[i+1][j]=='.')
{
res+=crt[used|1<<j];
}
next[used]=res%M; }
}
swap(crt,next);
}
}
printf("%d\n",crt[0]);
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&M))
{
for(int i=0; i<n; i++)
scanf(" %s",tu[i]);
solve();
}
return 0;
}

铺砖问题 (状态压缩dp)的更多相关文章

  1. ZOJ 2563 Long Dominoes(状态压缩DP)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1563 题目大意:在h*w的矩阵里铺满1*3的小矩阵,共有多少种方法 ...

  2. SGU131 - Hardwood floor(状态压缩DP)

    题目大意 给定一个N*M大小的矩形,要求你用1*2和2*2(缺个角)的砖块把矩形铺满(不能重叠),问总共有多少种铺法? 题解 受POJ2411的影响,怎么都没想到3,4,5,6这几种情况该怎么放置,看 ...

  3. hoj2662 状态压缩dp

    Pieces Assignment My Tags   (Edit)   Source : zhouguyue   Time limit : 1 sec   Memory limit : 64 M S ...

  4. POJ 3254 Corn Fields(状态压缩DP)

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4739   Accepted: 2506 Descr ...

  5. [知识点]状态压缩DP

    // 此博文为迁移而来,写于2015年7月15日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6jf.html 1.前 ...

  6. HDU-4529 郑厂长系列故事——N骑士问题 状态压缩DP

    题意:给定一个合法的八皇后棋盘,现在给定1-10个骑士,问这些骑士不能够相互攻击的拜访方式有多少种. 分析:一开始想着搜索写,发现该题和八皇后不同,八皇后每一行只能够摆放一个棋子,因此搜索收敛的很快, ...

  7. DP大作战—状态压缩dp

    题目描述 阿姆斯特朗回旋加速式阿姆斯特朗炮是一种非常厉害的武器,这种武器可以毁灭自身同行同列两个单位范围内的所有其他单位(其实就是十字型),听起来比红警里面的法国巨炮可是厉害多了.现在,零崎要在地图上 ...

  8. 状态压缩dp问题

    问题:Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Ev ...

  9. BZOJ-1226 学校食堂Dining 状态压缩DP

    1226: [SDOI2009]学校食堂Dining Time Limit: 10 Sec Memory Limit: 259 MB Submit: 588 Solved: 360 [Submit][ ...

  10. Marriage Ceremonies(状态压缩dp)

     Marriage Ceremonies Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu ...

随机推荐

  1. lintcode-167-链表求和

    167-链表求和 你有两个用链表代表的整数,其中每个节点包含一个数字.数字存储按照在原来整数中相反的顺序,使得第一个数字位于链表的开头.写出一个函数将两个整数相加,用链表形式返回和. 样例 给出两个链 ...

  2. LintCode-381.螺旋矩阵 II

    螺旋矩阵 II 给你一个数n生成一个包含1-n^2的螺旋形矩阵 样例 n = 3 矩阵为 [     [ 1, 2, 3 ],     [ 8, 9, 4 ],     [ 7, 6, 5 ] ] 标 ...

  3. thinkphp5 隐藏入口和支持pathinfo

    url里public目录的隐藏 其实正常思路的话这个url里的public本身就是不存在的,然后呢,其实也不叫隐藏public目录,这里只是考虑到有些童鞋可能还会按之前3.x时代的习惯来配置网站根目录 ...

  4. Agile.Net 组件式开发平台 - 驱动开发示例

    首先讲一下概念,此驱动非彼驱动.在Agle.Net中我们将组件规划成两种类型,一种是基于业务的窗体组件,一种是提供扩展功能的驱动组件. 打个比方例如一般系统中需要提供身份证读卡功能,然而市面上有很多种 ...

  5. MapperScannerConfigurer的原理

    原文地址:http://www.mybatis.org/spring/zh/mappers.html#MapperScannerConfigurer 为了代替手工使用 SqlSessionDaoSup ...

  6. Error:Unable to tunnel through proxy. Proxy returns "HTTP/1.1 400 Bad Request"

    (1) 网上下载了一个android应用:死活用不了,查了以下,原来是android studio版本不对,于是把android studio的版本从2.2 升级到3.0,后来发现没法升级,只能下载, ...

  7. request 域 个人理解

    1.转发到另一个servlet时候 地址还是输入当前的servlet 2.通过服务器转到另一个servlet时候 另一个servlet是最终接收端 端到端模式 相当于这个东西是发给自己的 只不过经过多 ...

  8. BZOJ 1296 粉刷匠(分组背包套DP)

    刚开始往网络流的方向想.建不出图... 因为每次只能对一行进行染色.每一行都是独立的. 对于每一行,因为格子只能染一次,所以可以发现这是一个多阶段决策问题,这个决策就是当前格子染0还是染1. 令dp[ ...

  9. BZOJ 1211 树的计数(purfer序列)

    首先考虑无解的情况, 根据purfer序列,当dee[i]=0并且n!=1的时候,必然无解.否则为1. 且sum(dee[i]-1)!=n-2也必然无解. 剩下的使用排列组合即可推出公式.需要注意的是 ...

  10. 【bzoj1143】[CTSC2008]祭祀river Floyd+网络流最小割

    题目描述 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组成的网络.每条河 ...