题意:略。

思路:由于每个大炮射程为2,所以如果对每一行状态压缩的话,能对它造成影响的就是上面的两行。

这里用dp[row][state1][state2]表示第row行状态为state2,第row-1行状态为state1时最多可以安放多少大炮。

则递推公式为:dp[i][K][J] = max(dp[i-1][L][K] + num[J])。其中num[J]表示状态J的二进制形式里有多少个1。

代码我是参考的别人的,觉得写得很好。

主要有一下几个地方:

1. 在判断一个数二进制形式有多少个1时,用 x & (x - 1) (具体见代码count_one函数)来判断。这种方法的时间复杂度就是x的二进制中1的个数。

假设有一个数二进制形式为1000位,其中只有一个1,则用最普通方法一位一位来数则需要计算1000次,而用该方法就是1次。

2. 在判断一个状态是否合法时(即该状态内不能有两个1距离在2以内),用x & (x << 1),x & (x << 2) (具体见代码ok函数)来判断,这与我一位一位比较的笨方法高下立见。

3. 在判断一个状态在地图中某一行是否合法时(即地图上的'H'处不能放置大炮),将地图的每一行转换成了一个数的二进制形式,'H' 为1,'P'为0。然后用数组line[]将每一行转换成的数字存储起来。之后假设要判断状态s能否放在第i行,则判断line[i] & s是否为0。如果不为0则说明该状态一定在'H'处出现了大炮,是不合法的。

除了上面这些,我在写完之后提交了几次发现wa。

经过检查,发现了原因:

别人的代码中,在求最终结果都是进行完dp后将dp数组遍历一次,求最大值即可。

而我写的则是在dp过程中记录最大值。这思想是没错的,但并没有注意到dp的几重循环是从第二行开始的,而地图第一行的dp值我是在进行dp前单独初始化的。这样子肯定错了,因为当最大值出现在第一行中时,我就记录不到了。后来我在第一行初始化时记录下最大值,又在接下来的dp过程中记录一下,就ac了,但不如直接在dp之后遍历一遍来得简洁,就作罢了。

 #include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int n, m, sta[], dp[][][], tot, line[], num[];
char map[][];
bool ok(int i)//判断状态i是否合法,即是否有两个1距离小于等于2
{
if (i & (i<<)) return ;
if (i & (i<<)) return ;
return ;
}
bool can(int row,int state)//判断状态state是否可以放在地图第row行
{
if (state & line[row]) return ;
return ;
}
int count_one(int x)//计数x的二进制状态有多少1
{
int res = ;
while (x)
{
res++;
x &= x - ;
}
return res;
}
int getdp()
{
memset(dp, -, sizeof(dp));
for (int i = ; i < tot; i++)
{
num[i] = count_one(sta[i]);
if (can(, sta[i]))
dp[][][i] = num[i];
}
for (int i = ; i <= n; i++)
for (int j = ; j < tot; j++) if (can(i, sta[j]))
for (int k = ; k < tot; k++)
{
if (sta[j] & sta[k]) continue;
for (int l = ; l < tot; l++)
{
if (sta[j] & sta[l]) continue;
if (dp[i-][l][k] == -) continue;
dp[i][k][j] = max(dp[i][k][j], dp[i-][l][k] + num[j]);
}
}
int res = ;
for (int i = ; i <= n; i++)
for (int j = ; j < tot; j++)
for (int k = ; k < tot; k++)
res = max(res, dp[i][j][k]);
return res;
}
int main()
{
//freopen("data.in", "r", stdin);
while (~scanf("%d%d",&n, &m) && n && m)
{
tot = ;
for (int i = ; i < (<<m); i++)
if (ok(i)) sta[tot++] = i;//预处理所有有效状态
memset(line, , sizeof(line));
for (int i = ; i <= n; i++)//将地图每一行的地形转换成二进制
{
scanf("%s", map[i]);
for (int j = ; j < m; j++) if (map[i][j] == 'H')
line[i] += (<<j);
}
printf("%d\n", getdp());
}
return ;
}

poj 1185 炮兵阵地 [经典状态压缩DP]的更多相关文章

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

    题目链接 Description 司令部的将军们打算在NM的网格地图上部署他们的炮兵部队.一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用& ...

  2. poj 1185 炮兵阵地(三维状态压缩dP)

    题目:http://poj.org/problem?id=1185 思路: d[i][j][k]表示第i行的状态为第k个状态,第i-1行的状态为第j个状态的时候 的炮的数量. 1表示放大炮, 地形状态 ...

  3. POJ 1185 炮兵阵地(状态压缩DP)

    题解:nState为状态数,state数组为可能的状态 代码: #include <map> #include <set> #include <list> #inc ...

  4. luogu P2704 炮兵阵地(经典状态压缩DP)

    方格有m*n个格子,一共有2^(m+n)种排列,很显然不能使用暴力法,因而选用动态规划求解. 求解DP问题一般有3步,即定义出一个状态 求出状态转移方程 再用算法实现.多数DP题难youguan点在于 ...

  5. poj -1185 炮兵阵地 (经典状压dp)

    http://poj.org/problem?id=1185 参考博客:http://poj.org/problem?id=1185 大神博客已经讲的很清楚了,注意存状态的时候是从1开始的,所以初始化 ...

  6. POJ 1185 炮兵阵地 经典的 状态压缩dp

    炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16619   Accepted: 6325 Description ...

  7. POJ 1185 炮兵阵地(状压DP)

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

  8. POJ1185炮兵阵地(状态压缩DP)

    POJ飞翔.数据弱 ZQOJ飞翔 数据强 Description 司令部的将军们打算在N×M的网格地图上部署他们的炮兵部队.一个N×M的地图由N行M列组成,地图的每一格可能是山地(用"H&q ...

  9. 洛谷 P2704 [NOI2001]炮兵阵地 (状态压缩DP+优化)

    题目描述 司令部的将军们打算在NM的网格地图上部署他们的炮兵部队.一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P" ...

随机推荐

  1. Diycode开源项目 磁盘图片缓存+自定义webViewClient+图片点击js方法

    1.磁盘图片缓存器DiskImageCache 1.1.这个类很多情况都可能用的到,耦合性很低,所以分开讲. 源代码: /* * Copyright 2017 GcsSloop * * License ...

  2. C语言用一维数组打印杨辉三角(原:无意中想到)

    本贴地址 ] = { }; a[] = , a[] = ; int i, j,m; ; i <= ; i++) //2-11 输出10行 { ; j > ; j--) //关键在这句,倒着 ...

  3. IOS开发学习笔记025-xib和storyboard

    stotyboard : 描述软件界面,大范围,比较适合整个软件的所有界面 xib文件的使用:描述软件界面,小范围,比较适合描述小界面 在xcode新建文件窗口可以看到两个文件,storyboard和 ...

  4. Python 操作 SQLite 数据库

    写在之前 SQLite 是一个小型的关系型数据库,它最大的特点在于不需要单独的服务.零配置.我们在之前讲过的两个数据库,不管是 MySQL 还是 MongoDB,都需要我们安装.安装之后,然后运行起来 ...

  5. [python][django学习篇][7]设计博客视图(1)

    1上网的流程: 打开浏览器,输入网址(http://zmrenwu.com/) 浏览器根据输入网址,完成以下几件事:1识别服务器地址,2将用户的浏览意图打包成一个http请求,发送给服务器,等待服务器 ...

  6. maven学习(八)——使用maven创建javaweb项目

    构建JavaWeb项目 1.创建JavaWeb项目 1.使用mvn archetype:generate命令,如下所示: mvn archetype:generate -DgroupId=com.my ...

  7. Mybatis通过接口的方式实现增删改查

    导入jar包 [mybatis] [oracle] 生成数据库 1.添加Mybatis的配置文件mybatis-config.xml 在src目录下创建一个mybatis-config.xml文件,如 ...

  8. 在iBatis中操作Blob数据类型

    这里的Blob数据类型指的是保存了文本的blob数据类型 直接读取blob类型存储的文本,可能会出现乱码,所以需要读取完后进行手动转码 这里使用ibatis作为持久层 SELECT urlconten ...

  9. iOS-------- Objective-C多态:动态类型识别+动态绑定+动态加载

    一.Objective-C多态 1.概念:相同接口,不同的实现 来自不同类可以定义共享相同名称的方法. 动态类型能使程序直到执行时才确定对象所属类型 动态类型绑定能使程序直到执行时才确定要对对象调用的 ...

  10. 被readLine()折腾了一把

    虽然写IO方面的程序不多,但BufferedReader/BufferedInputStream倒是用过好几次的,原因是: 它有一个很特别的方法:readLine(),使用起来特别方便,每次读回来的都 ...