本题的题眼很明显,N (1 <= N <= 150), M (1 <= M <= 10),摆明了是想让你用状态压缩dp。

整个思路如下:由于要填2*3或者3*2的芯片,那么就要找一个策略来判断到底能不能填。

精华1在此:

找到的策略是,记格子(i,j)的状态有三种:

状态0代表(i,j)和(i-1,j)均可用(可用包括非损坏和未占用)

状态1代表(i,j)可用但(i-1,j)不可用

状态2代表(i,j)和(i-1,j)均不可用。

这样设置状态后,我们可以将填芯片这个问题策略化描述:

即能够填芯片的情况无非两种:

其一横着填3*2的芯片,此时只需满足state(i,j)=0&&state(i,j+1)=0&&state(i,j+2)=0即可(在代码中用的是pre和now数组存放的两行状态)

其二是竖着填2*3的芯片,此时只需满足state(i,j)=0&&state(i,j+1)=0&&state(i-1,j)=0&&state(i-1,j+1)=0即可。

这样一来就可以从第一行开始深搜每一行可能出现的填芯片的情况并计数。

同时由于每个格子的状态只有3种,因此可以用3进制数对每一行的状态进行记录,也就是所谓的状态压缩。

比如如果某一行的状态为(1,1,0,2,2),转化为3进制数就是1*3^0+1*3^1+0*3^2+2*3^3+2*3^4。这样就将一行的状态用一个3进制数表示了。

精华2:在考虑完如何进行状态压缩后下一步就是如何用dp来求解了。

思路如下:既然可以将一行的状态记录为一个3进制数 t,那么递推关系不妨按行递推,也就是考虑从第一行开始,每增加一行,能填的芯片数目会增加多少。

而由精华1不难发现,只要知道新增行和上一行的状态,就可以推出填芯片的所有可能方案(这里显然需要搜索解决)。

因此考虑这样进行存储:设置一个dp[i][j]数组,其中i表示第几行,j表示该行当前的状态(也就是上文所说的压缩得到的3进制数)。

dp[i][j]的值表示以第i行为最后一行并且第i行状态为j的情况下所能填入的最大芯片数。

那么dp的目标就转化为求出所有dp[i][j]的值。

这里的特殊性在于,递推关系不再是一个简单的式子,而是通过深搜来更新的。

至此,思路就已经相当明确 了。

为了节约内存空间,在具体计算dp数组时用了滚动数组的方法(毕竟每次更新只需要保存两行状态就可以了)

一些小tips和犯过的错都记录在代码里了,以备温故知新。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int map[][];
int dp[][];
int now[];
int pre[];
int t[]={,,,,,,,,,,,};//3进制权重
int getstate(int a[]){
int tem=;
for(int i=;i<=m;i++){
tem+=a[i]*t[i];
}
return tem;
}
int getstring(int tem,int*a){
for(int i=;i<=m;i++){
a[i]=tem%;
tem=tem/;
}
//注意一下,注释里面是一开始写的错误程序;
//这样写的错误在于 不能完整的修改字符串,无法正确处理高位若干0的情况
// int i=0;
// while(tem!=0){
// a[++i]=tem%3;
// tem/=3;
// }
} void dfs(int i,int j,int prenum,int state){//深搜的典型框架
dp[i%][state]=max(dp[i%][state],prenum);
//dp[i%2][state]=prenum;//写成这样是错的 ,道理很简单,每种状态是可能被重复搜索到的,而
//在重复搜索到的时候就必须选择最大的那种情况才满足题意 ,一个简单的例子就是当某一行更新后状态为(2,2,2,2,2,2)
//则可能有两种情况出现 ,一种是3个2*3的芯片,一种是2个3*2的芯片。
int k;
if(j>=m)return;
if(j<m-&&now[j]==&&now[j+]==&&now[j+]==){
now[j]=now[j+]=now[j+]=;
k=getstate(now);
dfs(i,j+,prenum+,k);
now[j]=now[j+]=now[j+]=;
}
if(pre[j]==&&pre[j+]==&&now[j]==&&now[j+]==){
now[j]=;now[j+]=;
k=getstate(now);
dfs(i,j+,prenum+,k);
now[j]=;now[j+]=;
}
dfs(i,j+,prenum,state);
return;
} int main(void){
int d;
scanf("%d",&d);
while(d--){
int k;
scanf("%d%d%d",&n,&m,&k);
memset(map,,sizeof(map)); while(k--){
int a,b;
scanf("%d%d",&a,&b);
map[a][b]=;
}
for(int i=;i<=t[m+];i++){//一开始写的i=1
dp[][i]=-;
}
for(int i=;i<=m;i++){
pre[i]=map[][i]+;
}
int state=getstate(pre);
dp[][state]=;
for(int i=;i<=n;i++){//这里写的时候思路不连贯
for(int j=;j<=t[m+];j++){
dp[i%][j]=-;
}
for(int j=;j<=t[m+];j++){
if(dp[(i+)%][j]==-)continue;
getstring(j,pre);
for(int k=;k<=m;k++){
if(map[i][k]==)now[k]=;
else if(pre[k]==)now[k]=;
else{
now[k]=;
}
}
state=getstate(now);
dfs(i,,dp[(i+)%][j],state);
}
}
int ans=;
for(int i=;i<=t[m+];i++){
ans=max(dp[n%][i],ans);
}
printf("%d\n",ans);
}
return ;
}

POJ-1038 Bugs Integrated, Inc. (状压+滚动数组+深搜 的动态规划)的更多相关文章

  1. POJ 1038 Bugs Integrated, Inc. ——状压DP

    状态压缩一下当前各格子以及上面总共放了几块,只有012三种情况,直接三进制保存即可. 然后转移的时候用搜索找出所有的状态进行转移. #include <map> #include < ...

  2. POJ 1038 Bugs Integrated, Inc.(DFS + 三进制状压 + 滚动数组 思维)题解

    题意:n*m方格,有些格子有黑点,问你最多裁处几张2 * 3(3 * 2)的无黑点格子. 思路:我们放置2 * 3格子时可以把状态压缩到三进制: 关于状压:POJ-1038 Bugs Integrat ...

  3. POJ 1038 Bugs Integrated Inc (复杂的状压DP)

    $ POJ~1038~~\times Bugs~Integrated~Inc: $ (复杂的状压DP) $ solution: $ 很纠结的一道题目,写了大半天,就想练练手,结果这手生的.其实根据之前 ...

  4. POJ 1038 Bugs Integrated, Inc.

    AC通道 神坑的一道题,写了三遍. 两点半开始写的, 第一遍是直接维护两行的二进制.理论上是没问题的,看POJ discuss 上也有人实现了,但是我敲完后准备开始调了.然后就莫名其妙的以为会超时,就 ...

  5. poj1038 Bugs Integrated,Inc. (状压dp)

    题意:N*M的矩阵,矩阵中有一些坏格子,要在好格子里铺2*3或3*2的地砖,问最多能铺多少个. 我的方法好像和网上流传的方法不太一样...不管了.... 由数据范围很容易想到状压dp 我们设某个状态的 ...

  6. POJ1038 Bugs Integrated, Inc 状压DP+优化

    (1) 最简单的4^10*N的枚举(理论上20%) (2) 优化优化200^3*N的枚举(理论上至少50%) (3) Dfs优化状压dp O(我不知道,反正过不了,需要再优化)(理论上80%) (4) ...

  7. poj 1038 Bugs Integrated, Inc. 题解

    提供一种代码难度比较简单的做法(可能) 状态表示: 设置状态$ f[i][j] $,表示第 \(i\) 行状态为 \(j\) 的最大放置数,因为这是个阴间题,因为题目内存设置很小,所以要用滚动数组,存 ...

  8. poj 2288 Islands and Bridges ——状压DP

    题目:http://poj.org/problem?id=2288 状压挺明显的: 一开始写了(记忆化)搜索,但一直T: #include<iostream> #include<cs ...

  9. poj 2663 Tri Tiling (状压dp+多米诺骨牌问题+滚动数组反思)

    本来直接一波状压dpAC的 #include<cstdio> #include<cstring> #include<algorithm> #define REP(i ...

随机推荐

  1. 域名重新绑定ip时访问地址NotFount404

    情形描述:部署在A服务器IIS上的asp.net程序,搬迁到B服务器上,重新绑定域名和ip后.再访问网址时有些电脑能正常访问,而有些电脑报404 not found错误. 经分析发现是个人电脑网络设置 ...

  2. orm查询语法参考文章

    1.参考博客 http://blog.csdn.net/OyangYujun/article/details/45938905 ORMLite完全解析(三)官方文档第三章.自定义查询构造器 Custo ...

  3. 17. Letter Combinations of a Phone Number(bfs)

    Given a string containing digits from 2-9 inclusive, return all possible letter combinations that th ...

  4. HDU1530 最大流问题

    第一次写Dinic 然后贴一下 最基础的网络流问题 嘎嘎: #include <iostream> #include<cstdio> #include<string.h& ...

  5. Robot framework selenium driver download

    Chrome: https://sites.google.com/a/chromium.org/chromedriver/downloads http://npm.taobao.org/mirrors ...

  6. Permutation Bo (数学证明)

    当在两端时:共有n * (n - 1)种组合,满足条件的有,计算可得, counter = n * (n - 1) / 2. 其他位置时:共有n * (n - 1) * (n - 2) 种组合,满足条 ...

  7. asp.net web form 的缺点

    与mvc相比,web form 的缺点: 代码架构麻烦. 以页面或控件为单位,把逻辑放在了一起,代码架构简单.平铺直叙,修改.维护比较麻烦. 不方便单元测试.  功能堆加在了一起,不方便对单个的功能进 ...

  8. python os.path.join()

    >>> import os >>> path = '/Users/beazley/Data/data.csv' >>> # Get the las ...

  9. python 列表推导

    废话不多说,直接上代码 #coding=utf-8 def getitem(index, element): return '%d: %s' % (index, element) def getite ...

  10. js异步计时器

    js中同步和异步的区别: 1.同步会阻塞代码执行,而异步不会 2.alert 是同步,setTimeout 是异步 何时需要异步 1.在可能发生等待的情况 2.等待过程中不能像 alert 一样阻塞程 ...