poj 1185 炮兵阵地(状压DP)

和上一题有点类似。不过对于当前的第i行状态,除了牵涉到第i-1行的状态外,还和第i-2行的状态有关。
考虑枚举前两行的状态,来进行状态转移:
设dp[i][s][s1]表示第i行状态为s、第i-1行状态为s1时,能安置最多炮兵的数量。
分别枚举第i-1和i-2行的状态s1、s2,有:

dp[i][s][s1]=max(dp[i][s][s1],dp[i1][s1][s2])

对于该题,每行状态最多有2^10,显然直接枚举时间和空间上都是行不通的。
注意到,由于多个限制条件的存在,其实很多状态都是不合法的。于是可以把这些不合法的状态预先筛掉,将合法的状态用一个数组保存下来。这样,在枚举的时候直接枚举合法的状态即可。对于空间上,发现对于每一个行而言,合法的状态(即满足同一行炮兵不相互攻击的状态)实际上只有不超过60个,因此可以考虑用状态的下标来表示状态,这样空间复杂度也得到了优化。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define maxn 10
typedef __int64 LL;
char M[100][maxn];
int dp[100][60][60];
int state[60],cur[101],num[60];
bool judge1(int i,int s)
{
    if((cur[i]&s)!=s) return 0;
    return 1;
}

bool judge2(int s1,int s2)
{
    if(s1&s2) return 0;
    return 1;
}

int getnum(int s)
{
    int ans=0;
    while(s) {
        if(s&1) ++ans;
        s>>=1;
    }
    return ans;
}

int main()
{
    int i,j,k,p,n,m,S,cnt;
    while(~scanf("%d%d",&n,&m))
    {
        getchar();
        S=(1<<m);
        cnt=0;
        memset(dp,0,sizeof(dp));
        for(j=0;j<S;++j)
            if((!(j&(j>>1)))&&(!(j&(j>>2)))) {
                    num[cnt]=getnum(j);
                    state[cnt++]=j;
            }
        char c;
        for(i=0;i<n;++i){
            cur[i]=0;
            for(j=0;j<m;++j)
            {
                cin>>c;
                cur[i]=(cur[i]<<1)+(c=='P');
            }
        }


        for(i=0;i<cnt;++i)
            if(judge1(0,state[i])) dp[0][i][0]=num[i];

        for(i=0;i<cnt;++i){
            if(!judge1(1,state[i])) continue;
            for(j=0;j<cnt;++j)
                if(judge1(0,state[j])&&judge2(state[i],state[j])) dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+num[i]);
        }
        for(i=2;i<n;++i)
            for(j=0;j<cnt;++j)
            {
                if(!judge1(i-2,state[j])) continue;
                for(k=0;k<cnt;++k)
                {
                    if(!judge1(i-1,state[k])) continue;
                    for(p=0;p<cnt;++p)
                        if(judge1(i,state[p])&&judge2(state[p],state[j])&&judge2(state[p],state[k]))
                            dp[i][p][k]=max(dp[i][p][k],dp[i-1][k][j]+num[p]);
                }
            }
        int ans=0;
        for(i=0;i<cnt;++i){
            if(!judge1(n-1,state[i])) continue;
            for(j=0;j<cnt;++j) ans=max(ans,dp[n-1][i][j]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(poj 1185 炮兵阵地(状压DP))