poj1185炮兵阵地

题目链接:传送门

题目思路:状态压缩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;
}

 

posted @ 2016-05-09 16:47  Kurokey  阅读(185)  评论(0编辑  收藏  举报