本题的题眼很明显,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. Excel的导入导出功能

    POI组件的详细介绍文档: https://www.cnblogs.com/huajiezh/p/5467821.html .xls 对应 HSSFWorkbook book=new HSSFWork ...

  2. html5-块元素和内联元素

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  3. linux 查看python安装路径,版本号

    一.想要查看ubuntu中安装的python路径 方法一:whereis python     方法二:which python   二.想要查看ubuntu中安装的python版本号 python ...

  4. 为什么我们要使用HTTP Strict Transport Security?

    http://www.freebuf.com/articles/web/66827.html

  5. maven项目没有src/test/java和src/test/resources目录问题解决

    新建maven项目,如下图示: 只有src/main/java和src/main/resources两个目录,而没有src/test/java和src/test/resources,于是第一反应是没有 ...

  6. redux 数据规律

    counter increase info  todos 为 reducers 文件名 export default combineReducers({ todos, visibilityFilter ...

  7. 不懂RPC实现原理怎能实现架构梦

    RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在 ...

  8. MD5加密算法Java代码实现

    package com.app.utils; import java.math.BigInteger; import java.security.MessageDigest; import java. ...

  9. Docker学习笔记之为容器配置网络

    0x00 概述 在互联网时代,网络已经成为绝大多数应用进行数据交换的主要通道,Docker 作为集群部署的利器,在网络支持上也下了许多功夫.功能丰富和强大,并不代表使用复杂,在 Docker 的封装下 ...

  10. 用到临时表空间的几种SQL

    用到临时表空间的几种SQL CREATE INDEX SELECT ... ORDER BY SELECT DISTINCT ... SELECT ... GROUP BY SELECT ... UN ...