POJ 1185 炮兵阵地(状态dp)
2016-07-05 11:05
309 查看
这个题目和上一个种玉米的是一个类型,都是状态dp,用二进制位来表示当前的一个状态值,只不过比上一个稍微复杂了一点,需要用三维的数组来保存当前state。
题目:在一个N*M的矩阵上布置炮兵部队,只有平原可以布置,然后每个炮兵部队都有一个攻击范围,它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。
问:如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队?
考虑到每一行的状态只和前两行有关,考虑用dp来做。由于是求最多能放置的炮兵个数,就是求某一个状态下,它对应的炮兵个数最多,所以就想到dp方程肯定是那种dp[i]=max{dp[i-1]..}的形式。
我们用1来表示平原地形P,这样对于原始的矩阵,可以每一行的地形将对应一个01表示的地形状态,存到rState
中,用来检查该行炮兵的此种安排状态是否合法。
由于当前行和前两行有关系,所以得用3维矩阵来保存一个状态下最多的炮兵个数,用dp[i][curSt][preSt]表示当前第i行状态对curSt,前一行状态为preSt的最大炮兵数。
转移方程为dp[i][curSt][preSt]=max{dp[i-1][preSt][prepreSt]+curSt状态炮兵安排数量},这样求到最后一行之后,答案就是最后一行所有状态中最大的那个。
程序初始化的时候需要对第一行进行预处理,设置dp[0][st][0]=合法的st中1的个数。这样进行下面的计算的时候,由于0状态肯定是和所有状态兼容的,所以就不会影响计算结果。
代码如下:
题目:在一个N*M的矩阵上布置炮兵部队,只有平原可以布置,然后每个炮兵部队都有一个攻击范围,它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。
问:如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队?
考虑到每一行的状态只和前两行有关,考虑用dp来做。由于是求最多能放置的炮兵个数,就是求某一个状态下,它对应的炮兵个数最多,所以就想到dp方程肯定是那种dp[i]=max{dp[i-1]..}的形式。
我们用1来表示平原地形P,这样对于原始的矩阵,可以每一行的地形将对应一个01表示的地形状态,存到rState
中,用来检查该行炮兵的此种安排状态是否合法。
由于当前行和前两行有关系,所以得用3维矩阵来保存一个状态下最多的炮兵个数,用dp[i][curSt][preSt]表示当前第i行状态对curSt,前一行状态为preSt的最大炮兵数。
转移方程为dp[i][curSt][preSt]=max{dp[i-1][preSt][prepreSt]+curSt状态炮兵安排数量},这样求到最后一行之后,答案就是最后一行所有状态中最大的那个。
程序初始化的时候需要对第一行进行预处理,设置dp[0][st][0]=合法的st中1的个数。这样进行下面的计算的时候,由于0状态肯定是和所有状态兼容的,所以就不会影响计算结果。
代码如下:
#include<iostream> #include<stdio.h> #include<algorithm> #include<string> const int MaxState = 61; const int MaxCol = 12; const int MaxRow = 105; int dp[MaxRow][MaxState][MaxState];//dp[i][j][k]第i行当前状态为j,i-1行状态为k时能放置的最大炮兵数 int ValidSt[MaxState];//不考虑地形条件下满足条件的炮兵放置方式(状态) int PaoNum[MaxState];//每种状态放置的炮兵数量 int rState[MaxRow];//地形条件二进制表示数组 int n, m, valid_num; void initDp() { valid_num = 0; for (int i = 0; i < (1 << m); ++i) { if (!(i&(i << 1)) && !(i&(i << 2))) { ValidSt[valid_num] = i; int temp_i = i; int one_num = 0; while (temp_i) { temp_i &= temp_i - 1; one_num++; } PaoNum[valid_num++] = one_num;//不考虑地形条件下状态i可安装炮兵数量 } } for (int i = 0; i < valid_num; ++i) { if (!((~rState[0]) & ValidSt[i])) { dp[0][i][0] = PaoNum[i]; } } } int main() { //while (std::cin >> n >> m, n) { std::cin >> n >> m; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { char temp; std::cin >> temp; if (temp == 'P') { rState[i] |= (1 << (m - j - 1)); } } } memset(dp, -1, sizeof(dp)); initDp();//在不考虑地形条件下枚举所有满足不相邻条件的情况,并初始化dp[0][满足条件的状态][0] for (int i = 1; i < n; ++i) { for (int j = 0; j < valid_num; ++j) {// 第i行的第j中状态 if (!((~rState[i]) & ValidSt[j])) {//第i行炮兵安排状态j与地形是否符合 for (int k = 0; k < valid_num; ++k) {//遍历i-1行所有状态 if (!((~rState[i - 1]) & ValidSt[k]) && !(ValidSt[j] & ValidSt[k])) {//考虑地形条件和相邻上下行不可同时放炮兵,1表示在此位置放置炮兵 for (int t = 0; t < valid_num; ++t) {//遍历i-2行所有状态 if (!(~rState[i - 2] & ValidSt[t]) && !(ValidSt[j] & ValidSt[t])) {//!(ValidSt[j] & ValidSt[t])表示上下两行相同位置不能同时为1 dp[i][j][k] = std::max(dp[i][j][k], dp[i - 1][k][t] + PaoNum[j]); } } } } } } } int count = 0; for (int i = 0; i < valid_num; ++i) { for (int j = 0; j < valid_num; ++j) { count = std::max(count, dp[n - 1][i][j]); } } std::cout << count << std::endl; /*}*/ return 0; }
相关文章推荐
- java剧院管理系统,数据存储mysql
- eclipse设置新建jsp文件默认字符编码
- Android 难题解决
- 面向切面的AOP编程
- DNS预获取(dns-prefetch)
- Android-Studio常见报错解决方案
- 2016第28周二
- Component migration documentation
- 用parse_url() 解析URL中的详细信息
- nodejs系列学习:module-----(三)
- C#计算器编写代码
- POJ3258 River Hopscotch
- 关于 failed to find build tools revision 23.0.0 rc3的问题
- Linux sar命令
- MATLAB“out of memory"的一点总结
- LIBSVM学习(五)grid.py参数选择
- hypermesh打开显示fatal menu system error!
- 面向对象
- 对向量、方阵的求导
- hdwiki 框架简介