中文题目,题意就不说了。

不得不说这是一道十分经典的状态压缩DP的题目。

思路: 通过分析可以发现,第i行的格子能不能放大炮仅与第i-1和i-2行的放法有关,而与前面的放法无关,因此,如果我们知道了i-1行和i-2放的状态,那么,我们就可以推出第i行的可行的放法状态。因此可以看出i行的状态由它上面两行决定。

设dp[i][j][k]表示前i行,第i行用第j个状态放,第i-1行用第k个状态放的最大大炮的个数,那么状态转移方程就是:dp[i][j][k] = max(dp[i][j][k],dp[i-1][k][t]+num1[j]),其中num1[j]表示第i行用第j个状态放时,该行放的大炮的个数。通过枚举所有可行的状态则可以求出前n行能放的大炮的最大个数。注意,上述状态转移方程中的j,k,t,分别表示第i,i-1,i-2行的状态,他们不能发生冲突。

上面讲了一下具体的思想和转移方程,下面说说状态压缩,即:我们怎样表示每行放的大炮的状态,用什么表示?

可以看到,题目中列数最大为10,这不得不诱导我们往二进制位上面考虑。一个int型数长度位32位 > 10,那么我们可以用一个整数的二进制位中第i位表示该某行第i列放与不放,为1表示已放置大炮,为0表示未位置大炮,一个整数完全可以表示出所有状态事实上由于一行中的不同列放置大炮之间的距离必须不小于2,因此10列最多60个可行状态,而不是2^10个状态,也就是说dp数组中的j与k最大为60,可以另开一个数组来记录某行可行状态(跟离散化思想挺像的),数组中下标为j的数对应第j个状态,这样不至于导致dp数组开得太大超内存,也优化了时间。同时再记录下在状态j下,该状态中含有1的个数,即表示放的大炮的个数。

最后再说下位运算技巧:

1.给出状态j(对应的数为x)怎样得到该状态中1的个数?可以这么干: x &= (x-1),ret++; 其中x&(x-1)表示每次删去二进制中最后面那个1.

2.怎样知道某个数x表示的状态是否可行? 看 x & (x << 1) 和  x & (x << 2)是否都是0即可。

其他部分用的位运算都比较容易理解,比如置位x |= (1 << bit),检验状态是否冲突x & y 等等,就不一一说了。

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n, m, top;
int dp[111][70][70], map[111];
int status[70], num1[70];
int calNum1(int x){
int ret = 0;
while(x){ret++, x &= (x-1);}
return ret;
}
bool canPlace(int x){
if(x & (x << 1)) return false;
if(x & (x << 2)) return false;
return true;
}
void init(){
top = 0;
int UP = 1 << m;
for(int i = 0;i < UP;i ++){
if(canPlace(i)){
status[++top] = i;
num1[top] = calNum1(i);
}
}
}
int main(){
char str[111];
/* freopen("in.c", "r", stdin); */
while(~scanf("%d%d", &n, &m)){
memset(str, 0, sizeof(str));
memset(map, 0, sizeof(map));
memset(dp, 0, sizeof(dp));
for(int i = 1;i <= n;i ++) {
scanf("%s", str);
for(int j = 0;j < m;j ++)
if(str[j] == 'H') map[i] |= (1 << j);
}
init();
for(int i = 1;i <= top;i ++){
if(map[1] & status[i]) continue;
dp[1][i][1] = num1[i];
}
for(int i = 2;i <= n;i ++){
for(int j = 1;j <= top;j ++){
if(map[i] & status[j]) continue;
for(int k = 1;k <= top;k ++){
if(status[j] & status[k]) continue;
for(int t = 1;t <= top;t ++){
if(status[j] & status[t]) continue;
dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][t]+num1[j]);
}
}
}
}
int ans = 0;
for(int i = 1;i <= top;i ++)
for(int j = 1;j <= top;j ++)
ans = max(ans, dp[n][i][j]);
printf("%d\n", ans);
}
return 0;
}

POJ 1185 (状态压缩DP)的更多相关文章

  1. POJ 1185 状态压缩DP 炮兵阵地

    题目直达车:   POJ 1185 炮兵阵地 分析: 列( <=10 )的数据比较小, 一般会想到状压DP. Ⅰ.如果一行10全个‘P’,满足题意的状态不超过60种(可手动枚举). Ⅱ.用DFS ...

  2. POJ 1185 状态压缩DP(转)

    1. 为何状态压缩: 棋盘规模为n*m,且m≤10,如果用一个int表示一行上棋子的状态,足以表示m≤10所要求的范围.故想到用int s[num].至于开多大的数组,可以自己用DFS搜索试试看:也可 ...

  3. poj 2923(状态压缩dp)

    题意:就是给了你一些货物的重量,然后给了两辆车一次的载重,让你求出最少的运输次数. 分析:首先要从一辆车入手,搜出所有的一次能够运的所有状态,然后把两辆车的状态进行合并,最后就是解决了,有两种方法: ...

  4. poj 2688 状态压缩dp解tsp

    题意: 裸的tsp. 分析: 用bfs求出随意两点之间的距离后能够暴搜也能够用next_permutation水,但效率肯定不如状压dp.dp[s][u]表示从0出发訪问过s集合中的点.眼下在点u走过 ...

  5. Mondriaan's Dream(POJ 2411状态压缩dp)

    题意:用1*2的方格填充m*n的方格不能重叠,问有多少种填充方法 分析:dp[i][j]表示i行状态为j时的方案数,对于j,0表示该列竖放(影响下一行的该列),1表示横放成功(影响下一列)或上一列竖放 ...

  6. poj 2411 状态压缩dp

    思路:将每一行看做一个二进制位,那么所有的合法状态为相邻为1的个数一定要为偶数个.这样就可以先把所有的合法状态找到.由于没一层的合法状态都是一样的,那么可以用一个数组保存.由第i-1行到第i行的状态转 ...

  7. poj 3254 状态压缩DP

    思路:把每行的数当做是一个二进制串,0不变,1变或不变,找出所有的合法二进制形式表示的整数,即相邻不同为1,那么第i-1行与第i行的状态转移方程为dp[i][j]+=dp[i-1][k]: 这个方程得 ...

  8. poj 1185 状态压缩

    炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 27926   Accepted: 10805 Descriptio ...

  9. POJ 3254 状态压缩 DP

    B - Corn Fields Crawling in process... Crawling failed Time Limit:2000MS     Memory Limit:65536KB    ...

  10. poj 1185(状态压缩DP)

    poj  1185(状态压缩DP) 题意:在一个N*M的矩阵中,‘H'表示不能放大炮,’P'表示可以放大炮,大炮能攻击到沿横向左右各两格,沿纵向上下各两格,现在要放尽可能多的大炮使得,大炮之间不能相互 ...

随机推荐

  1. Memcached服务器安装、配置、使用详解

    管理memcached服务 启动Memcached 一般情况下,简单地可以使用类似如下形式,启动Memcached服务: /usr/local/bin/memcached -d -m 64 -I 20 ...

  2. Visual Assist安装、破解方法

    1.从各种渠道下载Visual Assist安装程序及破解补丁. 2.在路径(Win7):C:\Users\UserName\AppData\Local\Microsoft\VisualStudio\ ...

  3. 解决ie8下h5元素兼容性的问题

    HTML5的语义化标签以及属性,可以让开发者非常方便地实现清晰的web页面布局,加上CSS3的效果渲染,快速建立丰富灵活的web页面显得非常简单. HTML5的新标签元素有: <header&g ...

  4. javascripct流程语句

    1.条件选择       if 语句:只有当指定条件为true时,使用该语句来执行代码 if...else语句:当条件为true时执行代码,当条件为 false 时执行其他代码 if...else i ...

  5. Nginx+uWSGI+bottle 在Linux上部署

    在/data/lujianxing/bottle 文件夹中创建三个文件: bottle.py bottle的源文件 a.py from bottle import Bottle, run mybott ...

  6. poj 2778 DNA Sequence ac自动机+矩阵快速幂

    链接:http://poj.org/problem?id=2778 题意:给定不超过10串,每串长度不超过10的灾难基因:问在之后给定的长度不超过2e9的基因长度中不包含灾难基因的基因有多少中? DN ...

  7. Pair Project: Elevator Scheduler [电梯调度算法的实现和测试]:刘耀先-11061183,罗凡-11061174

    本次为我们两个人的第一次结对编程.从总体而言,我们对结对编程比单人编程略显不适应.但是经过一段时间的磨合,我们逐渐的习惯了这种编程方式. 1.  结对编程的优缺点 结对编程的优点: (1)       ...

  8. Memcached(七)Memcached的并发实例

    1. Memcached是什么?Memcached是分布式的内存对象缓存系统.  2. Memcached的基本数据结构是什么?Memcached是基于Key/Value对的HashMap.每一对,都 ...

  9. Logback 将日志分级别打印

    最近项目中用到了logback 记录日志,  关于为啥使用logback 请百度一下:  logback与Log4J的区别 好了,废话不多说,直奔主题, 研究了好久,终于将日志按级别将日志分文件打印出 ...

  10. [转载]C#多线程学习(一) 多线程的相关概念

    原文地址:http://www.cnblogs.com/xugang/archive/2008/04/06/1138856.html 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的 ...