[POJ 1185]炮兵陣地(狀壓DP)

Description


司令部的將軍們打算在N*M的網格地圖上部署他們的炮兵部隊。一個N*M的地圖由N行M列組成,地圖的每一格可能是山地(用”H” 表示),也可能是平原(用”P”表示),如下圖。在每一格平原地形上最多可以佈置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:
這裏寫圖片描述
如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它能夠攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。
現在,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內),在整個地圖區域內最多能夠擺放多少我軍的炮兵部隊。

Input


第一行包含兩個由空格分割開的正整數,分別表示N和M;
接下來的N行,每一行含有連續的M個字符(‘P’或者’H’),中間沒有空格。按順序表示地圖中每一行的數據。N <= 100;M <= 10。

Output


僅一行,包含一個整數K,表示最多能擺放的炮兵部隊的數量。

Sample Input


5 4
PHPP
PPHH
PPPP
PHPP
PHHP

Sample Output


6

Solution


感覺和上一題有點像
三維的狀壓DP,用了滾動數組
f[i][j][k] i表示所在行 j表示當前行狀態 k表示前一行狀態
預處理出一行中不會造成互相攻擊的狀態和每個狀態所含的1(炮兵部隊)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#define Max(a,b) (a>b?a:b)
using namespace std;
int n,m,f[2][1050][1050],map[100],state[1050],num[1050],cnt;
int count(int x)
{
    int y=0;
    while(x)
    {
        if(x&1)y++;
        x>>=1;
    }
    return y;
}
void init()
{
    memset(map,0,sizeof(map));
    memset(f,0,sizeof(f));
    cnt=0;
    for(int i=0;i<=(1<<m);i++)
    {
        bool b=0;
        if(i&(i<<1))b=1;
        if(i&(i<<2))b=1;
        if(!b)
        {
            state[++cnt]=i;
            num[cnt]=count(i);
        }
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=1;i<=n;i++)
        {
            char c[15];
            cin>>c;
            for(int j=0;j<m;j++)
            {
                map[i]<<=1;
                if(c[j]=='P')map[i]+=1;
            }
        }
        int ans=0,cur=0;
        for(int i=1;i<=n;i++)
        {
            cur^=1;
            for(int j=1;j<=cnt;j++)
            {   
                if((state[j]&map[i])!=state[j])continue;
                if(i==1)
                {
                    f[cur][j][1]=num[j];
                    ans=Max(ans,f[cur][j][1]);
                }
                else
                for(int k=1;k<=cnt;k++)
                {
                    if(state[k]&state[j])continue;
                    if(i==2)
                    {
                        f[cur][j][k]=Max(f[cur][j][k],f[cur^1][k][1]+num[j]);
                        ans=Max(ans,f[cur][j][k]);
                    }
                    else
                    for(int l=1;l<=cnt;l++)
                    {
                        if(state[l]&state[k])continue;
                        if(state[l]&state[j])continue;
                        f[cur][j][k]=Max(f[cur^1][k][l]+num[j],f[cur][j][k]);
                        ans=Max(ans,f[cur][j][k]);
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章