poj1185 [NOI2001]炮兵阵地

http://poj.org/problem?id=1185

三维装压dp,压缩上一行状态与本行状态,枚举上两行状态转移

第一维可以滚掉,实际复杂度只枚举符合情况的情况,每行状态不会超过60并非$2^M$,证明参见组合数

#include<cstdio>
#include<cstring>
#include<algorithm>

const int maxnm = 1001;
const int maxn = 11;
int n,m;
char a[maxn];
int cant[maxn*10];
int map[101][11];
bool check(int x,int i) {
    if(x&cant[i])return false;
    if(x&(x<<1)||x&(x<<2))return false;
    return true;
}
int dp[2][1<<maxn][1<<maxn];
int num[1<<maxn];
int main( ) {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)  {
        scanf("%s",a) ;
        for(int j=0;j<m;++j)
            if(a[j]==‘H‘)
            cant[i]|=(1<<j);
    }
    int po=(1<<m)-1;
    for(int k,i=1;i<=po;++i) {
        if(!check(i,0))continue;
        k=i;while(k) {
            num[i]+=(k&1);
            k>>=1;
        }
    }
    int ans=-1;
    for(int i=1;i<=n;++i) {
        for(int j=1;j<=po;++j) {
            if(!check(j,i))continue;
            for(int k=1;k<=po;++k) {
                if(!check(k,i-1)||(k&j)) continue;
                for(int p=1;p<=po;++p) {
                    if(!check(p,i-2)||(p&j)||(k&p)) continue;
                    dp[i&1][k][j]=std::max(dp[i&1][k][j],dp[(i&1)^1][p][k]+num[j]);
                }
                if(i==n)ans=std::max(ans,dp[n&1][k][j]);
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}
时间: 2024-08-30 08:25:54

poj1185 [NOI2001]炮兵阵地的相关文章

状压DP NOI2001 炮兵阵地

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

poj1185:炮兵阵地(状压dp)

也算是比较基础的状压dp了,跟做过的第二道比较又稍微复杂了一点 需要记录之前两行的状态.. 统计结果也稍有不同 另外还学习了一个得到一个整数二进制位 1 的个数的位运算方法 详见代码: #include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #include<ctype.h> using namespa

NOI2001 炮兵阵地

一道非常有意思的题目 很久之前考过 但那时候好像只会打裸搜索(捂脸跑 后来看题解的时候也是没有学状压的所以算是闲置了很久没动的题 昨天看到的时候第一反应是m<=10所以压m然后跑1-n枚举每一行 但是非常遗憾的是我一直在想横行怎么判断合法 所以比较sb的我想了好久都没想出来 于是又很怂逼地去看了题解(我怎么这么怂 横行合法只要位移然后与一下就可以判断了 竖行的合法就是根据上面两行的状态转移 f[i][j][k]表示的是第i行上一行状态为j本行状态为k的炮塔数量 特别注意零也是一种情况!!!昨天被

NOI2001炮兵阵地

题目传送门 PS:本道题目建议在对状压dp有一定了解的基础下学习,如有不懂可以先去学一下状压dp入门 题目大意:给你n*m个格子,有些格子可以用来部署军队,用P表示,有些则不能,用H表示,如果在一个格子上部署了军队,则上下左右各2个格子都不能部署军队,也就是呈十字架状,看到数据范围(n<=100,m<=10)很容易想到使用状压dp,因为m列数最大只有10,我们可以压缩每一行的状态,最大只有(1<<10)-1种状态,但是由于这一行的状态对下一行以及下两行都有影响,我们需要一个三维数组

【NOI2001】炮兵阵地

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

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

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