poj1185炮兵阵地

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>

using namespace std;

const int MAXN = 100 + 1;       //阵地行数
const int MAXM = 10 + 1;        //阵地列数
const int State_Num = 60 + 1;   //阵地列状态的压缩总数,合法状态总数最多60

int dp[MAXN][State_Num][State_Num], cur[MAXN], state[State_Num], tot;
char field[MAXN][MAXM];    //储存阵地
int n, m;    //阵地规模

/*
由于n <= 100, m <= 10,将阵地的列压缩。
dp[i][j][k]表示当第i行布置结束后,第i行的布置状态为j的情况下,
第i - 1行的状态为k,所能布置的最多的炮兵。
根据题意,我们可以删除一些状态。
删除的状态有:
1.山地不能布置炮兵
2.炮兵不能在垂直和水平的线上两格相邻。
cur[]数组用于储存输入的合法局面
state[]数组用于储存相邻的合法局面
*/

bool ok(int x)
{
    return !((x & (x << 1)) || (x & (x << 2)));
}

void init()    //保留不两格相邻的
{
    int limit = (1 << m);
    tot = 0;

    for (int i = 0; i < limit; i++)
    {
        if (ok(i)) state[tot++] = i;
    }
}

bool yes(int x, int i)
{
    return !(x & cur[i]);
}

int cal(int x)
{
    int res = 0;
    while (x)
    {
        if (x & 1) res++;
        x >>= 1;
    }
    return res;
}

void input()
{
    while (scanf("%d %d", &n, &m) != EOF)    //输入
    {
        init();
        memset(dp, 0, sizeof(dp));

        for (int i = 0; i < n; i++)
        {
            scanf("%s", field[i]), cur[i] = 0;
            for (int j = 0; j < m; j++)
                if (field[i][j] == 'H') cur[i] += (1 << (m - j - 1)); //用于判断状态是否合法(1)
        }

        for (int i = 0; i < tot; i++)    //初始化第一行
        {
            if (!yes(state[i], 0)) continue;
            for (int j = 0; j < tot; j++)
            {
                dp[0][i][j] = cal(state[i]);
            }
        }

        for (int i = 1; i < n; i++)    //计算当前行,枚举上两行的状态
        {
            for (int j = 0; j < tot; j++)    //枚举当前行的状态
            {
                if (!yes(state[j], i)) continue;
                for (int k = 0; k < tot; k++)
                {
                    if (!yes(state[k], i - 1)) continue;
                    for (int l = 0; l < tot; l++)
                    {
                        if (!yes(state[l], i - 2)) continue;
                        if (((state[j] & state[k]) == 0) && ((state[j] & state[l]) == 0) && ((state[k] & state[l]) == 0))
                        {
                            dp[i][j][k] = max(dp[i][j][k], dp[i - 1][k][l] + cal(state[j]));
                        }
                    }
                }
            }
        }

        int ans = 0;    //计算答案

        for (int i = 0; i < tot; i++)
            for (int j = 0; j < tot; j++)
                ans = max(ans, dp[n - 1][i][j]);

        cout << ans << endl;
    }
}

int main()
{
    input();
    return 0;
}

poj1185炮兵阵地

时间: 2024-08-03 13:38:50

poj1185炮兵阵地的相关文章

poj1185炮兵阵地状压dp

压前两行的状态很容易想到,但是 直接搞  (1<<10) * (1<<10)  空间时间都明显受不了, 但是经过高人指点,你会发现:枚举每一行可行的状态,其实并不多,预先打表处理,不用 1->(1<<10)枚举每一种状态.. 然后记忆化搜就ok了. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include &

[poj1185]炮兵阵地_状压dp

炮兵阵地 poj-1185 题目大意:给出n列m行,在其中添加炮兵,问最多能加的炮兵数. 注释:n<=100,m<=10.然后只能在平原的地方建立炮兵. 想法:第2到状压dp,++.这题显然是很经典的.设状态dp[i][j][k]表示第i行的状态为j,i-1行的状态为k的最多炮兵数.在转移时,枚举所有的合法炮兵排列(此处的合法数目是根据一行全为平原的时候能放置的合法炮兵数目),然后内层循环枚举dp[i-1]的i-1状态,进行特判更新即可.统计答案时,我们只需对于dp[n]的所有可能状态求最大值

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

[POJ1185]炮兵阵地

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

poj1185炮兵阵地 正确代码及错误代码分析

Solution:状态压缩 因为设置炮兵的局限性(同行两炮兵相差要大于2),一行10个数最多有60种可能性(程序计算) 其中判断可能性的好方法是: if ((i & (i << 1))==0 && (i & (i << 2))==0             && (i & (i >> 1))==0 && (i & (i >> 2))==0) 代表不能有左1,左2,右1,右2相邻的

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

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

[POJ1185]炮兵阵地(状压DP)

题目链接:http://poj.org/problem?id=1185 这个和之前的不一样,在于某个点影响的范围是两格.那么dp(cur,pre,i)表示第i行状态为cur,i-1行状态为pre时可以有多少种放法.转移的时候枚举ppre,就是i-2行即可.照葫芦画瓢 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7 ┓┏┓┏┓┃ 8 ┛┗┛┗┛┃ 9 ┓┏┓┏┓┃ 10 ┛┗┛┗┛┃ 1

[状压dp]POJ1185 炮兵阵地

中文题 题意不再赘述 对于中间这个“P” 根据dp的无后效性 我们只需考虑前面的 就变成了 只需考虑: 也就是状压前两行 具体与HDOJ的4539类似: 看HDOJ 4539 仅仅是共存状态的判断不同 1 //#include <bits/stdc++.h> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using n

炮兵阵地

poj1185:http://poj.org/problem?id=1185 题意:这道题太经典了,看到题目就知道题意,故题意略. 题解:经典的状压dp.以前觉得dp是个很难的东西,做了这一题之后发现,dp其实根本不难,真的,而且很好打. 思维过程:拿到题之后,由于之前做过,所以知道是状压dp.接着想怎么解决.普通的dp,不要考虑障碍,这一题中有障碍限制.多以第一步要处理这个障碍.想到了用这样的方式来解决.把出现h的地方标记为1,其余记0,从右到左,从低位到高位,求出这个数,然后枚举状态的时候,