poj2411 状态压缩-铺地板题型-轮廓线解法(最优)
解法参考博客https://blog.csdn.net/u013480600/article/details/19569291
一种做法是先打出所有的状态,即满足上下配对的所有可能方案,然后再逐行进行枚举计数
dp[i][s]=sum{dp[i-1][t]},t是所有和s配对的状态
打状态时要注意如果i-1的j是0,那么i的j必定是1,i剩下的位置要必须一对对填入1,也可以用0填入,即枚举i行的横放砖块的起始位置k即可,如果i-1的k或k+1有一个不是1,那么显然不能放下
/*
对于每一行,用11表示一个横放的方块,用0表示竖放方块的第一格,1表示竖放方块的第二格
枚举i-1行的状态,推出i行的状态
如果i-1行的j位置是0,那么第i行的j必须是1,第i行剩下的地方要么填连续两个1要么填0
第n行的状态必须都是1
*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define ll long long
ll dp[][<<];
int n,m,w,path[][];//所有可能的配对方案
void get(int m){
for(int i=;i<=(<<m)-;i++)
for(int j=;j<=(<<m)-;j++){
int ok=;
for(int k=;k<m;k++)
if(ok){
if( !(i&(<<k)) ){//i的第k位是0
if(!(j&(<<k))){
ok=;break;
}
}
else{//i的第k位是1,其实是在枚举j状态横放的起点位置
if(!(j&(<<k)))continue;//j的第k位是0
++k;
if(k>=m || !(i&(<<k))){//i没有第k+1位或者i的第k+1位是0,所以j在k位置不可能横放了
ok=;break;
}
else if( (j&(<<(k-))) && !(j&(<<k)) ){//j的状态是10,显然不可能
ok=;break;
}
}
}
if(ok)path[w][]=i,path[w++][]=j;
}
}
int main(){
while(cin>>n>>m,n){
w=;
if(m>n)swap(n,m);
get(m);
memset(dp,,sizeof dp);
dp[][(<<m)-]=;
for(int i=;i<n;i++)
for(int j=;j<w;j++)
dp[i+][path[j][]]+=dp[i][path[j][]];
printf("%lld\n",dp[n][(<<m)-]);
}
}
另外一种解法
/*
用0和1表示某个位置放不放砖块,如果是0则表示让下一行来补,如果是1则有两种可能,一种是横放,一种是填补上一行的0
对应这三种情况,可以搜索出所有可能的配对情况
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll dp[][<<];
int path[][],n,m,w;
void get(int c,int pre,int now){
if(c>m)return;
else if(c==m){
path[w][]=pre;
path[w++][]=now;
return;
}
get(c+,(pre<<)|,now<<);//后一行不放,前一行必定是1
get(c+,pre<<,(now<<)|);//前一行0,后一行必定是1
get(c+,(pre<<)|,(now<<)|);//前一行横放,后一行也是横放
}
int main(){
while(cin>>n>>m,m){
w=;
if(m>n)swap(n,m);
get(,,);
memset(dp,,sizeof dp);
dp[][(<<m)-]=;//初始条件不可忽略!
for(int i=;i<n;i++)
for(int j=;j<w;j++)
dp[i+][path[j][]]+=dp[i][path[j][]];
printf("%lld\n",dp[n][(<<m)-]);
}
}
最后是轮廓线解法:遍历一次方格,每扫到一个方格时枚举所有可能的轮廓线,然后由上一个格子(上一个状态的轮廓线)推出当前状态的轮廓线所对应的摆放方案数,以此推到最后一个格子
使用滚动dp数组,覆盖之前无效的信息即可
/*
轮廓线解法
*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define ll long long
ll dp[][<<];
int n,m,cur;
void update(int a,int b){//a是包含m位的旧状态,b是包含m+1位的新状态
if(b&(<<m))//如果b的首位是1才进行转移,即如果b的首位是0的话是不成立的
dp[cur][b^(<<m)]+=dp[cur^][a];
}
int main(){
while(cin>>n>>m,m){
if(m>n)swap(m,n);
memset(dp,,sizeof dp);
cur=;
dp[][(<<m)-]=;//边际条件算第一种方案:需要由这个初始状态推导出其他状态
for(int i=;i<n;i++)
for(int j=;j<m;j++){
cur^=;
memset(dp[cur],,sizeof dp[cur]);//把上一轮的状态清零
for(int k=;k<(<<m);k++){//枚举当前所有可能的轮廓线状态
//三种可能
update(k,k<<);//[i,j]不放
if(i && !(k&(<<(m-))))update(k,(k<<)^(<<m)^);//向上摆放
if(j && !(k&))update(k,(k<<)^);//向左摆放
}
}
printf("%lld\n",dp[cur][(<<m)-]);
}
}
poj2411 状态压缩-铺地板题型-轮廓线解法(最优)的更多相关文章
- POJ2411 状态压缩dp
POJ2411 http://poj.org/problem?id=2411
- [ACM_动态规划] 轮廓线动态规划——铺放骨牌(状态压缩1)
Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, af ...
- 状态压缩dp(hdu2167,poj2411)
hdu2167 http://acm.hdu.edu.cn/showproblem.php?pid=2167 给定一个N*N的板子,里面有N*N个数字,选中一些数字,使得和最大 要求任意两个选中的数字 ...
- HihoCoder第九周 状态压缩 二 与POJ2411总结
在此我向各位博友求助,特别想知道除了HihoCoder上面的结果要对1e9+7取余之外,这两道题还有什么其他的问题,都是骨牌覆盖问题,都是状态压缩+dp,为什么我能过poj2411的程序过不了Hiho ...
- 转 状态压缩DP
引入 首先来说说“状态压缩动态规划”这个名称,顾名思义,状态压缩动态规划这个算法包括两个特点,第一是“状态压缩”,第二是“动态规划”. 状态压缩: 从状态压缩的特点来看,这个算法适用的题目符合以下的条 ...
- 状态压缩dp小结
最近一段时间算是学了一些状态压缩的题目,在这里做个小结吧 首先是炮兵布阵类题目,这类题目一开始给定一个矩形,要求在上面放置炮兵,如果在一格放了炮兵那么周围的某些格子就不能放炮兵,求最大能放置炮兵的数量 ...
- DP大作战—状态压缩dp
题目描述 阿姆斯特朗回旋加速式阿姆斯特朗炮是一种非常厉害的武器,这种武器可以毁灭自身同行同列两个单位范围内的所有其他单位(其实就是十字型),听起来比红警里面的法国巨炮可是厉害多了.现在,零崎要在地图上 ...
- hdu1565 网络流或状态压缩DP
对于网络流有一个定理: 最小点权覆盖集=最大网络流: 最大点权独立集=总权值-最小点权覆盖集: 网络流解法代码如下: #include<cstdio> #include<iostre ...
- SGU131 - Hardwood floor(状态压缩DP)
题目大意 给定一个N*M大小的矩形,要求你用1*2和2*2(缺个角)的砖块把矩形铺满(不能重叠),问总共有多少种铺法? 题解 受POJ2411的影响,怎么都没想到3,4,5,6这几种情况该怎么放置,看 ...
随机推荐
- modbus 寄存器介绍
modbus 的查询命令 命令 地址开始(两个地址) 地址长度(两个地址) 检验 01 xx xx xx ...
- python 数据分析3
本节概要 pandas简介 安装 pip install pandas pandas的2个主要数据结构:DataFrame 和 Series Series series是一种类似于一维数组的对象,它由 ...
- python中的私有变量
class Test1: def f1(self): self.name ="张三" self.__age = 20 #使用名称变形实现私有变量 print(self.name) ...
- Path for IClasspathEntry must be absolute:
关掉eclipse, 删除workspace工作目录下面的.metadata文件,看不到.metadata文件就 "ctril + H" 就可以看到了.然后重新打开eclipse, ...
- Linux 脚本/脚本实现思路
- swap扩展
没有独立的分区,本地回环设备(使用软件来模拟实现硬件) 创建一个镜像文件 https://blog.csdn.net/linuxnews/article/details/51271875 有独立的分区
- gprof使用介绍【转】
转自:https://blog.csdn.net/linquidx/article/details/5916701 gprof 1.1 简介 gprof实际上只是一个用于读取profile结 ...
- Mudo C++网络库第五章学习笔记
高效的多线程日志 日志(logging)有两个意思: 诊断日志(diagnostic log), 常用日志库提供日志功能; 交易日志(transaction log), 用于记录状态变更, 通过回放日 ...
- Android-创建一个简单的用户接口-(补day2内容)
如果按照之前的布局设置,那么输入框和按钮组件的大小就会是刚好满足它们的内容的.如图1. 图1.输入框和按钮宽度设置为”wrap_content” 这样的设置是可以满足按钮的,但不能满足输入框的要求,因 ...
- hue报错StructuredException: timed out (code THRIFTSOCKET): None的处理
通过hue的web界面进行hive的sql查询,无法显示结果并报错timeout 报错如下:[28/Jul/2017 11:23:29 +0800] decorators ERROR error ru ...