炮兵阵地 POJ 1185

状态压缩dp
记忆化搜索
这是放棋子的模型,因为攻击范围,所以要保存两行的状态,枚举。
f[i][s1][s2]表示第i行的状态为s1,i-1行为s2的时候前i行已经放置的炮的个数,那么f[i][s1][s2]=s2的状态1的个数+max(f[i-1][s2][jj]),只要枚举jj,且jj是合法的。我是倒着做的。详见注释

#include <cstdio>

#include <cstring>

#include <algorithm>

using namespace std;

const int maxn=100;

int n,m,num=0;

int mapstate[maxn];

long long f[101][maxn][maxn];

int s[maxn],c[maxn];



int find1(int x){

	    x=(x & 0x55555555) + ((x >>1 ) & 0x55555555);

	    x=(x & 0x33333333) + ((x >>2 ) & 0x33333333);

	    x=(x & 0x0F0F0F0F) + ((x >>4 ) & 0x0F0F0F0F);

	    x=(x & 0x00FF00FF) + ((x >>8 ) & 0x00FF00FF);

	    x=(x & 0x0000FFFF) + ((x >>16) & 0x0000FFFF);

	    return x;

	}

bool check(int x){

    // the current line is legal unless no 11 or 101

    if((x & (x<<1))!=0)return false;

    if((x & (x<<2))!=0)return false;

    return true;

}

void init(){

    // to in the map

    char ch[12];

    for(int i=1;i<=n;i++){

        scanf("%s",&ch);

        for(int j=0;j<m;j++){

            mapstate[i]<<=1;

            mapstate[i]+=(ch[j] == 'P')?0:1;//plain means 0

        }

    }



    int x=(1<<m)-1;

	//保存单行的合法状态

    for(int i=0;i<=x;i++){

        if(check(i)){

            s[++num]=i;// the legal state

            c[num]=find1(i);// the number of 1

        }

    }

}

inline bool legal(int s1,int s2){

//同一列上没有1

    if((s[s1] & s[s2])!=0)return false;

    return true;

}

void dfs(int i,int s1,int s2){//s1 current line s2 front line

//f[i][s1][s2]表示第i行的状态为s1,i-1行为s2的时候前i行已经放置的炮的个数

//倒着循环的

    if(((s[s1] & mapstate[i])!=0)){//当前行与地图不冲突

        for(int j=1;j<=num;j++)

            f[i][s1][s2]=0;

        return;

    }

    if((s[s2] & mapstate[i-1])!=0){

        f[i][s1][s2]=0;

        return;

    }

    if(!legal(s1,s2)){//这两行是否不冲突

        f[i][s1][s2]=0;

        return;

    }

    long long temp=-1;

    for(int jj=1;jj<=num;jj++){

        if(legal(s2,jj) && legal(s1,jj)){

            if(f[i-1][s2][jj]==-1)//这里保证了i=2即到底的时候,有边界限制

                dfs(i-1,s2,jj);

            temp=max(temp,f[i-1][s2][jj]);//返回值的时候这里的最优值已经确定

        }

    }

    f[i][s1][s2]=temp+c[s1];//当前行的个数加上

}

int main(){

    scanf("%d%d",&n,&m);

    memset(s,0,sizeof(s));

    memset(c,0,sizeof(c));

    memset(mapstate,0,sizeof(mapstate));

    init();

    memset(f,-1,sizeof(f));

    //the edge

    for(int i=1;i<=num;i++){

        if((s[i] & mapstate[1])==0){

            for(int j=1;j<=num;j++){

                f[1][i][j]=c[i];//第一行的合法状态的个数

            }

        }

    }

    long long mmax=-1;

    for(int i=1;i<=num;i++){

        for(int j=1;j<=num;j++){

            if(f[n][i][j]==-1)

                dfs(n,i,j);

            mmax=max(mmax,f[n][i][j]);

        }

    }

    printf("%I64d",mmax);

    return 0;

}

  

你可能感兴趣的:(poj)