Poj 1185/Hrbust 1844 炮兵阵地【状压dp】
来源:互联网 发布:轻而易举瓷砖软件 编辑:程序博客网 时间:2024/06/16 21:08
Description
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
Input
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
Output
Sample Input
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
Sample Output
6
Source
思路:
如果小伙伴们对状压dp还不是很了解的话,大家可以先考虑考虑做做这个题并参考参考我的详解:http://blog.csdn.net/mengxiang000000/article/details/51075506
1、设定dp【i】【j】【k】表示现在dp过程到了第i行,第i行状态为j第i-1行状态为k的最大放置炮台的个数。对于状态来讲,我们使用十进制数来保存,其含义为:其转化成2进制之后,对应位数字为1表示这个位子上放置炮台,数字为0表示这个位子上不放置炮台。
2、那么不难理解:
dp【i】【j】【k】=max(dp【i】【j】【k】,dp【i-1】【k】【l】+第i行状态j放置的炮台个数);
虽然这个状态转移方程式一点问题都没有,但是呢,它的设定会超内存。所以呢,我们再次设定:
dp【i】【j】【k】表示现在dp过程到了第i行,第i行的可行状态编号为j,第k行的可行状态编号为k的最大放置炮台的个数
e.g:某一行:PHHP
可行方案有三种:
1
8
9
对应我们给其编号为;
1 1
2 8
3 9
因为可行方案并不会太多,所以我们可以更多的释放内存。
3、那么我们在输入完图之后,初始化搞定这个可行状态的保存问题:
①设定tmp=这一行H的情况,e.g:PHPP,tmp=2;(我们设定最左边的是第一位)
②枚举这一行所有可能的状态j【(0<=j<(1<<m)】,然后判断这种状态是否合法,首先,j&tmp==0,表示在H的地方,我们没有放置不合法的炮台。
③然后我们将这种状态保存入数组a【i】【contz】,并且记录当前状态中有多少个1(就是有多少个炮台),记录在add【i】【contz】中。
对应代码:
int judge(int j,int k,int l){ if((j&k)!=0)return 0; if((j&l)!=0)return 0; if((k&l)!=0)return 0; return 1;} int end=(1<<m); for(int i=0;i<n;i++) { int tmp=0; int contz=0; for(int j=0;j<m;j++) { if(aa[i][j]=='H') { tmp+=(1<<j); } } for(int j=0;j<end;j++) { if(judgerow(j)==1) { if((j&tmp)==0) { int sum=0; int tmpp=j; while(tmpp) { if((tmpp&1)!=0)sum++; tmpp/=2; } a[i][contz]=j; add[i][contz++]=sum; } } } kk[i]=contz; }
4、然后我们进行状态转移,我们从第二行开始搞定这个问题(如果输入只有一行,我们单独处理)
①枚举第i行的状态j和i-1行的状态k,得到dp【i】【j】【k】的三个元素i,j,k。
②然后枚举一个状态l,得到dp【i-1】【k】【l】的三个元素i-1,k,l。
③然后判断一下j,k,l三个状态有没有上下矛盾的情况,如果没有,维护dp【i】【j】【k】的值。
对应代码:
int judgerow(int j){ if((j&(j<<1))!=0)return 0; if((j&(j<<2))!=0)return 0; if((j&(j>>1))!=0)return 0; if((j&(j>>2))!=0)return 0; return 1;}for(int i=1;i<n;i++) { for(int jj=0;jj<kk[i];jj++) { for(int ll=0;ll<kk[i-1];ll++) { int j=jj; int k=ll; int addd=add[i][jj]; if(i==1) { addd+=add[i-1][ll]; if(judge(a[i][j],a[i-1][k],0)==1) { dp[i][j][k]=max(dp[i][j][k],addd); } continue; } for(int pp=0;pp<kk[i-2];pp++) { int l=pp; if(judge(a[i][j],a[i-1][k],a[i-2][l])==1) { dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+addd); } } } } }
5、整个思路和核心代码搞定了之后:
ans=max(dp【n-1】【i】【j】);
维护一下即可。
完整Ac代码:
#include<stdio.h>#include<iostream>#include<string.h>using namespace std;//int dp[150][1024][1024];int dp[150][120][120];int kk[150];int add[150][1050];int a[150][1050];char aa[150][20];int n,m;int judge(int j,int k,int l){ if((j&k)!=0)return 0; if((j&l)!=0)return 0; if((k&l)!=0)return 0; return 1;}int judgerow(int j){ if((j&(j<<1))!=0)return 0; if((j&(j<<2))!=0)return 0; if((j&(j>>1))!=0)return 0; if((j&(j>>2))!=0)return 0; return 1;}int main(){ while(~scanf("%d%d",&n,&m)) { memset(dp,0,sizeof(dp)); for(int i=0;i<n;i++) { scanf("%s",aa[i]); } int end=(1<<m); for(int i=0;i<n;i++) { int tmp=0; int contz=0; for(int j=0;j<m;j++) { if(aa[i][j]=='H') { tmp+=(1<<j); } } for(int j=0;j<end;j++) { if(judgerow(j)==1) { if((j&tmp)==0) { int sum=0; int tmpp=j; while(tmpp) { if((tmpp&1)!=0)sum++; tmpp/=2; } a[i][contz]=j; add[i][contz++]=sum; } } } kk[i]=contz; } for(int i=1;i<n;i++) { for(int jj=0;jj<kk[i];jj++) { for(int ll=0;ll<kk[i-1];ll++) { int j=jj; int k=ll; int addd=add[i][jj]; if(i==1) { addd+=add[i-1][ll]; if(judge(a[i][j],a[i-1][k],0)==1) { dp[i][j][k]=max(dp[i][j][k],addd); } continue; } for(int pp=0;pp<kk[i-2];pp++) { int l=pp; if(judge(a[i][j],a[i-1][k],a[i-2][l])==1) { dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+addd); } } } } } if(n==1) { int ans=0; for(int i=0;i<kk[0];i++) { ans=max(add[0][i],ans); } printf("%d\n",ans); continue; } int ans=0; for(int i=0;i<kk[n-1];i++) { for(int j=0;j<kk[n-2];j++) { ans=max(dp[n-1][i][j],ans); } } printf("%d\n",ans); }}
- Poj 1185/Hrbust 1844 炮兵阵地【状压dp】
- POJ 1185--炮兵阵地(状压dp)
- poj 1185 炮兵阵地 状压DP
- POJ 1185 炮兵阵地 (状压DP)
- POJ 1185 炮兵阵地(状压dp)
- 炮兵阵地 - POJ 1185 状压dp
- POJ 1185 炮兵阵地(状压DP)
- poj 1185 炮兵阵地 状压DP
- POJ 1185-炮兵阵地(状压DP)
- POJ 1185 炮兵阵地 (状压DP)
- POJ 1185 炮兵阵地(状压dp)
- poj 1185 炮兵阵地 状压dp
- poj 1185 炮兵阵地 【状压DP】
- poj 1185 炮兵阵地(状压DP)
- POJ 1185 炮兵阵地 状压DP
- poj 1185 炮兵阵地(状压dp)
- POJ 1185 炮兵阵地 (状压dp)
- poj 1185 炮兵阵地 状压dp
- java中finally语句快会不会执行的问题
- PHP用户注册邮箱验证激活账号
- Spring系列之与Struts的集成
- centos7安装android sdk时报错Unable to run mksdcard SDK
- Unity3D ParticleSystem粒子系统属性总结
- Poj 1185/Hrbust 1844 炮兵阵地【状压dp】
- Spring3 MVC请求参数获取的几种方法
- JS找茬游戏
- Fram 驱动部分
- POJ-2891 Strange Way to Express Integers (数论:扩展欧几米德定理)
- kvm qemu内幕介绍
- Antenna Placement--匈牙利算法
- Lucene教程(一) 创建索引
- Java连接MySQL数据库并且执行建表和插入数据