您的位置:首页 > 其它

poj1185炮兵阵地

2016-05-09 16:47 295 查看
题目链接:传送门

题目思路:状态压缩DP(详见注释)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <cctype>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <climits>
#define lson root<<1,l,mid
#define rson root<<1|1,mid+1,r
#define fi first
#define se second
#define seg int root,int l,int r
#define ping(x,y) ((x-y)*(x-y))
#define mst(x,y) memset(x,y,sizeof(x))
#define mcp(x,y) memcpy(x,y,sizeof(y))
#define Min(x,y) (x<y?x:y)
#define Max(x,y) (x>y?x:y)
using namespace std;
#define gamma 0.5772156649015328606065120
#define MOD 100000007
#define inf 0x3f3f3f3f
#define N 10005
#define maxn 1000050
typedef long long LL;
typedef pair<int,int> PII;

char str[105];
int pic[105],n,m,ans,all;
int state[1005],num[1005],cnt;///state里面保存的是可以放炮台的情况
int dp[105][105][105];        ///二进制位为1表示放炮台,和pic中的不一样

int judge(int x){           ///判断x是否满足左右两格之内没有炮台
if((x&(x<<1))||(x&(x<<2)))return 0;
int res=0;              ///如果符合条件统计该情况下放了多少炮台
while(x){
res+=(x&1);
x>>=1;
}
num[cnt]=res;
return 1;
}
void init(){                        ///初始化有多少个状态符合题意(每个点左右两格之内无炮台)
cnt=0;
for(int i=0;i<all;++i)
if(judge(i))
state[cnt++]=i;
}

int main(){
int i,j,k,l;
while(scanf("%d%d",&n,&m)!=EOF){
mst(pic,-1);                ///-1在计算机中二进制表示为全1,,初始化这样做的好处当n为1时不用出错
mst(dp,0);                  ///因为pic[2]二进制全都为1,没有一个状态满足
all=1<<m;
for(i=1;i<=n;++i){
pic[i]=0;
scanf("%s",str);
for(j=0;j<m;++j)
pic[i]=pic[i]<<1|(str[j]=='P'?0:1); ///这里为0可以放炮台,为1不能放
}
ans=0;
init();
for(i=0;i<cnt;++i){                 ///初始化第一行状态
if(pic[1]&state[i])continue;
dp[1][i][0]=num[i];
ans=Max(ans,num[i]);            /*****/ ///注意从这就要开始保存答案,不然会WA
}
for(i=0;i<cnt;++i){                 ///第二行状态
if(pic[2]&state[i])continue;    ///在这里体现出了初始化为-1的好处,当n==1时,不会错
for(j=0;j<cnt;++j){
if(pic[1]&state[j])continue;
dp[2][i][j]=Max(dp[2][i][j],dp[1][j][0]+num[i]);
ans=Max(ans,dp[2][i][j]);
}
}
for(i=3;i<=n;++i){
for(j=0;j<cnt;++j){ ///第i行状态
if(pic[i]&state[j])continue; ///选取的state与pic冲突,不可取,下面同理
for(k=0;k<cnt;++k){///第i-1行状态
if(state[j]&state[k])continue;
if(state[k]&pic[i-1])continue;
for(l=0;l<cnt;++l){///第i-2行状态
if(state[l]&pic[i-2])continue;
if(state[l]&state[k])continue;
if(state[l]&state[j])continue;
dp[i][j][k]=Max(dp[i][j][k],dp[i-1][k][l]+num[j]);
ans=Max(ans,dp[i][j][k]);
}
}     ///要dp数组的维度所表示的意义,i表示第几行,j表示在第i行选取的是状态state[j]
}         ///k表示i-1行选取的是state[k]状态,因为上面两行对当前行都会有影响
}             ///所以更新状态时才会有那么多判断
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: