poj 1185 && NYOJ 85 炮兵阵地(状态压缩dp)

炮兵阵地

时间限制:2000 ms  |  内存限制:65535 KB

难度:6

描述
司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。

现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

输入
第一行输出数据测试组数X(0<X<100)

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

输出
每组测试数据输出仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。
样例输入
1
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
样例输出
6

分析:dp[i][j][k]表示排列到第i行,第i-1行的状态为s[j],第i-2行的状态为s[k]时,最多可以放置多少个炮兵。

则dp[i][j][k] = max(dp[i][j][k], dp[i-1][j][k] +num[i])。第一行和第二行特殊处理。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 105;
int Map[N];
int dp[N][65][65];  //dp[i][j][k]表示放第i行时,第i-1行为第j个状态,第i-2行为第k个状态最多可以放多少个炮兵

int s[N], num[N];
int n, m, p;

bool check(int x) {  //判断本行的炮兵是否互相攻击
    if(x & (x >> 1)) return false;
    if(x & (x >> 2)) return false;
    return true;
}

int Count(int x) {  //计算状态为x时可以放多少个炮兵
    int i = 1, ans = 0;
    while(i <= x) {
        if(x & i) ans++;
        i <<= 1;
    }
    return ans;
}

void Init() {
    p = 0;
    memset(s, 0, sizeof(s));
    memset(num, 0, sizeof(num));
    for(int i = 0; i < (1 << m); i++) { //预处理出合法状态
        if(check(i)) {
            s[p] = i;
            num[p++] = Count(i);
        }
    }
}

int main() {
    char ch;
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        if(!n && !m) {
            printf("0\n");
            continue;
        }
        memset(dp, 0, sizeof(dp));
        memset(Map, 0, sizeof(Map));
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                cin >> ch;
                if(ch == 'H')
                    Map[i] = Map[i] | (1 << (m - 1 - j));  //P为0,H为1
            }
        }
        Init();
//        printf("p = %d\n", p);
//        for(int i = 0; i < p; i++) {
//            printf("s[%d] = %d, num[%d] = %d\n", i, s[i], i, num[i]);
//        }
        for(int i = 0; i < p; i++) { //求第一行最多放多少
            if(!(Map[0] & s[i]))
                dp[0][i][0] = num[i];
        }
        for(int i = 0; i < p; i++) {  //前两行最多放多少
            if(!(Map[1] & s[i])) {
                for(int j = 0; j < p; j++) {
                    if((!(s[i] & s[j]))) {
                        dp[1][i][j] = max(dp[1][i][j], dp[0][j][0] + num[i]);
                    }
                }
            }
        }
        for(int r = 2; r < n; r++) {  //枚举行数
            for(int i = 0; i < p; i++) {  //当前行的状态
                if(!(s[i] & Map[r])) {
                    for(int j = 0; j < p; j++) {  //上一行的状态
                        if(!(s[j] & Map[r-1])) {
                            if(!(s[i] & s[j])) {
                                for(int k = 0; k < p; k++) {  //上上一行的状态
                                    if(!(s[k] & Map[r-2])) {
                                        if(!(s[j] & s[k])) {
                                            if(!(s[i] & s[k])) {
                                                dp[r][i][j] = max(dp[r][i][j], dp[r-1][j][k] + num[i]);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        int ans = 0;
        for(int i = 0; i < p; i++) {
            for(int j = 0; j < p; j++) {
                if(ans < dp[n-1][i][j])
                    ans = dp[n-1][i][j];
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
时间: 2024-12-08 05:57:00

poj 1185 && NYOJ 85 炮兵阵地(状态压缩dp)的相关文章

poj 1185 炮兵阵地(状态压缩dp)

Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格.图上其它白色网格均攻击不

POJ1185 炮兵阵地 状态压缩DP

B - 炮兵阵地 Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-06-29) Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用&quo

POJ 1185 NOI 2001 炮兵阵地 状压DP

题目大意:给出一个地图,有两种点,P点可以站人,H点不能站人.每放一个人就会对他上下左右各两个格子产生影响,产生影响的格子不能放人.问最多能放多少个人. 思路:数据范围指引解题的方向.题中给出M<=10,这是一个很小的数字,2^10也不过才1024,用这个来dp就轻松多了.于是我们先预处理出每一行可能出现的状态,要注意一行中不能有两个距离<2.大表之后发现,每一行最多只能有60个左右.现在可以放心做O(n^3×m)的dp了.处理上下几行的关系的时候要注意status&status_==

炮兵阵地[状态压缩DP]

看到这一道题其实和玉米田很类似,只不过多记录了前两行,其他大体细节差不多,注意滚动数组似乎不滚动更快??? Code #include<bits/stdc++.h> using namespace std; const int N=105; struct state{ int num[105],a[105]; }st[105]; int n,m; char s[15]; int f[3][105][105]; void getstate(int k,char *s){ int t=0; for

HDU1185:炮兵阵地(状态压缩)

Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格.图上其它白色网格均攻击不

poj 2411 Mondriaan&#39;s Dream(状态压缩+dp)

 题意:用1*2砖块铺满n*m的房间. 思路转自:http://www.cnblogs.com/scau20110726/archive/2013/03/14/2960448.html 因为这道题输入范围在11*11之间,所以可以先打表直接输出.......... 状态压缩DP 经典覆盖问题,输入n和m表示一个n*m的矩形,用1*2的方块进行覆盖,不能重叠,不能越出矩形边界,问完全覆盖完整个矩形有多少种不同的方案 其中n和m均为奇数的话,矩形面积就是奇数,可知是不可能完全覆盖的.接着我们来看

POJ - 1185 炮兵阵地 (状态压缩)

题目大意:中文题目就不多说大意了 解题思路: 1.每行最多仅仅有十个位置,且不是山地就是平原,那么就能够用1表示山地,0表示平原,将每一行的状态进行压缩了 2.接着找出每行能放炮兵的状态.先不考虑其它行放炮兵和该行的山地对其造成的影响,枚举出全部的状态.并记录每一个状态下放的炮兵数量 在上述情况下放炮兵.仅仅须要考虑同行的炮兵是否会相互攻击就能够了,那仅仅须要推断他的左边第一个位置是否有炮兵和左边第二个位置是否有炮兵就可以 3.接着进行dp,由于影响因素有两个.一个是上一行的状态,还有一个是上两

poj 2441 Arrange the Bulls(状态压缩dp)

Description Farmer Johnson's Bulls love playing basketball very much. But none of them would like to play basketball with the other bulls because they believe that the others are all very weak. Farmer Johnson has N cows (we number the cows from 1 to

poj - 1691 - Painting A Board(状态压缩dp)

题意:N(1 <= N <= 15)个矩形,每个矩形要涂上指定的颜色C(1 <= C <= 20),如果给一个矩形涂色,那么与它相邻的上方矩形必须已经涂色,问最少要取几次画笔. 题目链接:http://poj.org/problem?id=1691 -->>状态:dp[S][color] 表示达到状态 S 且最后一次涂色为 color 时的最小取画笔数 状态转移方程:dp[S][color] = min(dp[S][color], dp[sub][i]); 或者 dp[