博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
poj1185 炮兵阵地【状压DP】
阅读量:4317 次
发布时间:2019-06-06

本文共 2858 字,大约阅读时间需要 9 分钟。

炮兵阵地
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 32802   Accepted: 12650

Description

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 

Input

第一行包含两个由空格分割开的正整数,分别表示N和M; 
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

Output

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

Sample Input

5 4PHPPPPHHPPPPPHPPPHHP

Sample Output

6

Source

 
题意:
有一个n*m的格子有的格子是山,有的格子是平原。只有平原可以放一个炮兵。炮兵的攻击范围是两格,也就是说如果一个格子放了炮兵,他上下左右两格里不能再放炮兵。问这样n*m的地图中,可以最多放多少炮兵。
 
思路:
因为m是小于10的,每个格子又只有放或者不放的状态。所以我们可以考虑状压。用一个十进制数来表示某一行的放炮兵状态。第j位是1表示第j列的格子放了炮兵,0表示没有放。同理,地图上一行的山或是平原的状态也可以用十进制数来表示。
以行数i作为状态转移的阶段,转移的时候需要看的是前面两行的状态。用dp[i][j][k]表示第i行的状态时j,第i-1行的状态是k时,前i行最多的炮兵数。
显然dp[i][j][k] = max(dp[i -1][k][l]) + j的二进制表示中1的个数
并且并不是所有0~2^m-1的数都是可行的,必须要是二进制中1之间的间隔大于等于2的数才可以。
那么我们就可以首先预处理出所有可行的数,每次遍历这些数就可以了。对于每一行还需要去判断一下是否满足当前的地图状态。
刚开始用把平原当1,山当0,这样判断的时候位运算会有点麻烦。所以后面改成了用山当1,这样只需要用& == 0就可以了。
debug了超级久,今天终于找到bug了,太菜了。码力堪忧......
1 #include 
2 #include
3 #include
4 #include
5 #include
6 7 using namespace std; 8 typedef long long LL; 9 #define inf 0x3f3f3f3f 10 11 const int maxn = 105; 12 int n, m, mostm; 13 int dp[maxn][80][80], dixing[maxn]; 14 int cntone[80], S[80], cnt; 15 16 bool valid(int i, int x) 17 { 18 if (dixing[i] & x)return false; 19 else return true; 20 } 21 22 int get_one(int x) 23 { 24 int res = 0; 25 while (x) { 26 res += (x & 1); 27 x >>= 1; 28 } 29 return res; 30 } 31 32 bool ok(int x) 33 { 34 if (x & (x << 1))return false; 35 if (x & (x << 2)) return false; 36 return true; 37 } 38 39 void getS() 40 { 41 cnt = 0; 42 mostm = 1 << m; 43 for (int i = 0; i < mostm; i++) { 44 if (ok(i)) { 45 S[cnt] = i; 46 cntone[cnt] = get_one(i); 47 cnt++; 48 } 49 } 50 } 51 52 int main() 53 { 54 while (scanf("%d%d", &n, &m) != EOF) { 55 getS(); 56 memset(dixing, 0, sizeof(dixing)); 57 for (int i = 1; i <= n; i++) { 58 char tmp[20]; 59 scanf("%s", tmp); 60 //printf("%s", tmp + 1); 61 for (int j = 0; j < m; j++) { 62 //cout<
<
<< (m - 1 - j)); 65 } 66 } 67 } 68 69 memset(dp, -1, sizeof(dp)); 70 dp[0][0][0] = 0; 71 int ans = 0; 72 for (int j = 0; j < cnt; j++) { 73 if (valid(1, S[j])) { 74 dp[1][j][0] = cntone[j]; 75 ans = max(ans, dp[1][j][0]); 76 } 77 } 78 //cout<<1<<" "<
<

 

转载于:https://www.cnblogs.com/wyboooo/p/9796829.html

你可能感兴趣的文章
css取消a标签在移动端点击时的背景颜色
查看>>
Annotation(注解)
查看>>
MySQL(四)--练习题
查看>>
高效掌握C#第五回---猜单词游戏
查看>>
07-Java 中的IO操作
查看>>
uclibc,eglibc,glibc之间的区别和联系【转】
查看>>
Java魔法堂:找外援的利器——Runtime.exec详解
查看>>
mysql数据库存放路径
查看>>
TestNG(五)常用元素的操作
查看>>
解决 Visual Studio 点击添加引用无反应的问题
查看>>
通过镜像下载Android系统源码
查看>>
python字符串格式化 %操作符 {}操作符---总结
查看>>
windows 不能在 本地计算机 启动 Apache
查看>>
iOS开发报duplicate symbols for architecture x86_64错误的问题
查看>>
Chap-6 6.4.2 堆和栈
查看>>
【Java学习笔记之九】java二维数组及其多维数组的内存应用拓展延伸
查看>>
C# MySql 连接
查看>>
网络抓包分析方法大全
查看>>
sql 数据类型
查看>>
android 截图
查看>>