POJ 1185 状态DP

这个题目是个挺难表示的状态DP,因为不但要考虑上下还要考虑左右,在DP里面就没有什么下了咯,但也至少除了考虑左右还要考虑上

所以先枚举出在同一行满足条件的状态 即 某状态 若 s&(s<<1) 或者(s&(s<<2)) 则说明同一行的炮塔在射击范围内,要去掉。

然后就是考虑不同行的了,只要上一行和上上行的状态不冲突即可

于是就有了如下状态 

dp[i][j][k]代表第i行状态为k,上一行的状态为j时的最大值。

于是它的子状态就是 dp[i-1][w][j]代表上一行的状态为j 上上行的状态为w的最大值。

于是 dp[i][j][k]=max(dp[i][j][k],dp[i-1][w][j]+calc[k]) (calc代表某个状态中1的个数 即炮塔的数目)。

需要枚举四层循环 中间通过状态的对比来去掉一些没用的状态。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 11
using namespace std;
int dp[105][1<<N-3][1<<N-3];
int A[105],m,n,calc[1<<N],num,state[1<<N];
void init()
{
    num=0;
    for (int i=0;i<(1<<m);i++)
    {
        int tmp=0;
        if (i&(i<<1) || i&(i<<2)) continue; //左右有冲突 跳过。
        state[num]=i;
        for (int j=0;j<m;j++)
        {
           if ((1<<j)&i)
                tmp++;
        }
        calc[num++]=tmp; //算出某个状态中的含1的个数
    }
}
bool fit(int a,int b)//判断上下某个状态是否冲突
{
    if (a&b) return 0;
    return 1;
}
void DP()
{
    int ans=0;
    for (int i=0;i<num;i++) //先预处理第一行的情况
    {
        if (!fit(state[i],A[1]))
            continue;
        dp[1][0][i]=calc[i];
        ans=max(ans,dp[1][0][i]);
    }
    for (int i=2;i<=n;i++)
    {
        for (int k=0;k<num;k++) //这里的是先枚举k还是j 没什么大关系,两个状态彼此独立。
        {
            for (int j=0;j<num;j++)
            {
                if (!fit(state[j],state[k])|| !fit(state[k],A[i]) || !fit(state[j],A[i-1]))//有冲突就直接跳过
                    continue;
                for (int w=0;w<num;w++)
                {
                    if (!fit(state[j],state[w])|| !fit(state[k],state[w]))
                        continue;
                    if (!fit(state[w],A[i-2])) continue;
                    dp[i][j][k]=max(dp[i][j][k],dp[i-1][w][j]+calc[k]);
                    ans=max(ans,dp[i][j][k]);
                }
            }
        }
    }
    printf("%d\n",ans);
}
int main()
{
    char c;

    while (scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        memset(dp,0,sizeof dp);
        for (int i=1;i<=n;i++)
        {
            getchar();
            A[i]=0;
            for (int j=0;j<m;j++)
            {
                c=getchar();
                if (c=='H')
                    A[i]+=1<<j; //这里故意把H设置为1,是为了正好用上面的fit函数,如果有状态把炮塔建在H上,就是不可取的状态。
               // cout<<c;
            }
           // cout<<endl;
        }
        DP();

    }
    return 0;
}

 

posted @ 2014-03-17 21:22  KRisen  阅读(179)  评论(0编辑  收藏  举报