POJ 1185 炮兵陣地 (狀態壓縮dp)

這題的狀態我是這樣定義的:
dp[i][j][k] 表示在第k行前,當前狀態是i,上一行的狀態是j的時候,最多可以放多少個炮。

一開始我定義的時候,沒有中間那個j,但是後來想想似乎不對。
如果這樣定義的話,碰到這種情況就不對了。

HPH
PHP
HPH

第三行,按照(錯誤)定義,是從第二行來的,第二行是從第一行來。
但是這時的第三行和第一行明顯不可以同時存在於第二列上。
這樣的定義就會算進去,會錯誤。

所以需要多加一維。

另外這題i,j並不是真正的狀態,而是狀態集合的下標。
因爲通過運算,發現,一行最多隻有60種可行情況。

所以數組不需要開到1<<10這樣大,只要開比60多就行了。

代碼如下:

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
using namespace std;

char grid[120][12];
int able[100][120];
int pt[120];
int dp[100][100][120];
int n,m;

void init()
{
    memset(grid,0,sizeof(grid));
    memset(able,0,sizeof(able));
    memset(pt,0,sizeof(pt));
    memset(dp,0,sizeof(dp));
}

bool test1(int now,int row)
{
    for(int i=m-1;i>=0;i--)
    {
        if(now%2==1 && grid[row][i]=='H') return false;
        now=now/2;
    }
    return true;
}

int test2(int S)
{
    return (((S<<1)&S) | ((S<<2)&S));
}

int bitcount(int S)
{
    int cnt=0;
    /*while(S>0)
    {
        cnt+=(S&1);
        S=(S>>1);
    }*/
    while(S>0)
    {
        if(S%2==1) cnt++;
        S=S/2;
    }
    return cnt;
}

int main()
{
    while(cin>>n>>m)
    {
        init();
        for(int i=0;i<n;i++)
        {
            scanf("%s",grid[i]);
        }

        for(int i=0;i<n;i++)
        {
            for(int S=0;S<(1<<m);S++)
            {
                if(test1(S,i)==false) continue;
                if(test2(S)!=0) continue;
                able[pt[i]][i]=S;
                pt[i]++;
            }
        }
        //printf("%d\n",pt[0]);

        //枚舉第一行
        for(int i=0;i<pt[0];i++)
        {
            int S=able[i][0];
            dp[i][0][0]=bitcount(S);
        }

        //枚舉第二行
        for(int i=0;i<pt[1];i++)
        {
            int S=able[i][1];
            for(int j=0;j<pt[0];j++)
            {
                int P=able[j][0];
                if( (P&S)!=0 ) continue;
                dp[i][j][1]=max(dp[i][j][1],dp[j][0][0]+bitcount(S));
            }
        }

        //正式開始
        for(int r=2;r<n;r++)
        {
            for(int i=0;i<pt[r];i++)
            {
                int S=able[i][r];
                for(int j=0;j<pt[r-1];j++)
                {
                    int P=able[j][r-1];
                    if((P&S)!=0) continue;
                    for(int k=0;k<pt[r-2];k++)
                    {
                        int T=able[k][r-2];
                        if((T&S)!=0 || (P&T)!=0) continue;
                        dp[i][j][r]=max(dp[i][j][r],dp[j][k][r-1]+bitcount(S));
                    }
                }
            }
        }

        int ans=0;
        for(int i=0;i<100;i++)
        {
            for(int j=0;j<100;j++)
            {
                ans=max(ans,dp[i][j][n-1]);
            }
        }
        printf("%d\n",ans);

    }


    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章