POJ 1185 状态压缩DP 炮兵阵地

题目直达车:   POJ 1185 炮兵阵地

分析:

 

列( <=10 )的数据比较小, 一般会想到状压DP.

Ⅰ、如果一行10全个‘P’,满足题意的状态不超过60种(可手动枚举)。

Ⅱ、用DFS搜出所有可能表示状态的整数(二进制1表示可以放,0则不能)。

Ⅲ、对每一行的地行进行状态处理(p[i]表示第i行地形的状态),二进制‘H’转1,‘P’转0;

Ⅳ、用dp[i][j][k]表示第i行,且i行状态为j,i-1行状态为k时,最多能放置的量。

Ⅴ、对于第i行的可行状态必须满足:

               ⒈  j & k =0 且 j & t =0 (t为第i-2行放置状态)与前两行匹配,即不互相攻击。

               ⒉  j & p[i] = 0 与地形匹配,即只放平原地带。

Ⅵ、转移方程:dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][t]+num[j])

      (num[j]为第j种状态中放置炮兵的数量)   

第一次做状态DP,  参考(题解报告)的思路才敲出来

代码: 

 

#include<iostream>

#include<cstdio>

#include<cmath>

#include<cstring>

#include<vector>

using namespace std;

int p[105],dp[105][65][65];

vector<int>M[11];

int a[11],n,m;

void DFS(int k,int t){  ///搜索m=t时如果全为'P'可以表示状态的整数

    if(k==t){

        int p=0;

        for(int i=0;i<t;++i)

            if(a[i]) p=p|(1<<i);

        M[t].push_back(p);  /// 记下能表示状态的整数

        return;

    }

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

        if(i&&((k&&a[k-1])||(k>1&&(a[k-1]||a[k-2])))) continue;

        a[k]=i;

        DFS(k+1,t);

    }

}

int main(){  

    for(int i=1;i<=10;++i) DFS(0,i); 

    while(~scanf("%d%d",&n,&m)&&n+m){

        p[0]=0; 

        ///num[i]记下用第i种状态(整数M[m][i]表示) 中设了多少炮兵部队

        int num[65], len=M[m].size();

        for(int i=0;i<len;++i)

            num[i]=__builtin_popcount( M[m][i] ); ///计算M[m][i]中二进制中1的个数 

        memset(dp,0,sizeof(dp));

        int Max=0;

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

            char ch[105]; scanf("%s",ch);

            p[i]=0;

            //预处理地形(1代表'H',0代表'P')

            for(int j=0;j<m;++j) if(ch[j]=='H') p[i]|=(1<<j);

            if(i==1){ //初始化第一行所有布置情况

                for(int k=0; k<len; ++k)

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

                        if(!(M[m][k]&p[1])) dp[1][k][j]=num[k];

                        else dp[1][k][j]=0;

                        Max=max(Max,dp[1][k][j]);

                    }

                continue;

            }

            for(int j=0; j<len; ++j)//当前行

                if(!(M[m][j]&p[i])) //与 地形匹配

                    for(int k=0; k<len; ++k)//i-1

                        if(!(M[m][k]&p[i-1])&&!(M[m][k]&M[m][j]))//与 地形、i-1行匹配

                            for(int t=0; t<len; ++t)//i-2

                                //与 地形、i-1行、i-2行匹配

                                if(!(M[m][t]&p[i-2])&&!(M[m][t]&M[m][k])&&!(M[m][t]&M[m][j])){ 

                                    dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][t]+num[j]);

                                    if(i==n)Max=max(dp[i][j][k],Max);

                                }           

        }

        printf("%d\n",Max);

    }

    return 0;

}




 


 

你可能感兴趣的:(poj)