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这几种情况该怎么放置,看 ...
随机推荐
- python 08
函数 函数定义: 你可以定义一个由自己想要功能的函数,以下是简单的规则: 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号(). 任何传入参数和自变量必须放在圆括号中间.圆括号之间可以用于 ...
- [kuangbin带你飞]专题一 简单搜索(回顾)
A - 棋盘问题 POJ - 1321 注意条件:不能每放一个棋子,就标记一行和一列,我们直接枚举每一行就可以了. AC代码: #include<iostream> #include< ...
- Django学习手册 - admin后台 切换成中文显示/添加数据表
Django admin后台管理 切换成中文界面: 站点显示为中文: 在setting 里面修改 LANGUAGE_CORE = 'zh-Hans' 字段名显示中文 class Test(models ...
- android gradle tools 3.X中dependencies, implementation和compile区别
在3.0版本中,compile 指令被标注为过时方法,而新增了两个依赖指令,一个是implement 和api,这两个都可以进行依赖添加,但是有什么区别呢? api 指令 完全等同于compile指令 ...
- Queue和BlockingQueue的使用以及使用BlockingQueue实现生产者-消费者
Java提供了两种新的容器类型:Queue和BlockingQueue. Queue用于保存一组等待处理的元素.它提供了几种实现,包括:ConcurrentLinkedQueue,这是一个先进先出的并 ...
- 国产 WEB UI 框架 (收费)-- Quick UI,Mini UI
国产 WEB UI 框架 (收费)-- Quick UI,Mini UI : http://www.uileader.com/ http://www.miniui.com/
- php无法连接mysql问题解决方法总结
http://www.163ns.com/zixun/post/5295.html 本文章总结了在php开发中可能会常常碰到的一些php连接不了mysql数据库的一些问题总结与解决方法分享,有 ...
- weblogic和was的巡检报告模板
weblogic巡检报告模板 https://max.book118.com/html/2017/0710/121553357.shtm 用jrockit How to tell Our WebLo ...
- 修改Linux主机名与IP之间的映射关系
linux主机版本: Distributor ID: UbuntuDescription: Ubuntu 14.10Release: 14.10 一.修改linux主机名 1.使用hostname命令 ...
- git与eclipse集成之更新特性分支代码到个人特性分支
1.1. 更新特性分支代码到个人特性分支 在基于特性分支开发的过程中,存在多人向特性分支提交代码的情况,开发者需要关注特性分支代码与个人分支代码保持同步,否则可能导致提交代码冲突. 具体代码同步步骤: ...