HLOJ490 狀壓例題4 炮兵陣地

題面

題目描述
司令部的將軍們打算在NM的網格地圖上部署他們的炮兵部隊。一個NM的地圖由N行M列組成,地圖的每一格可能是山地(用”H” 表示),也可能是平原(用”P”表示),如下圖。在每一格平原地形上最多可以佈置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:
這裏寫圖片描述
輸入格式
第一行包含兩個由空格分割開的正整數,分別表示N和M;
接下來的N行,每一行含有連續的M個字符(‘P’或者’H’),中間沒有空格。按順序表示地圖中每一行的數據。N <= 100;M <= 10。
輸出格式
僅一行,包含一個整數K,表示最多能擺放的炮兵部隊的數量。

題解

很明顯,一個炮兵部隊的擺放受到前兩行的制約。
狀態:
f[i][j][k] 代表第i行狀態是j,第i-1行狀態是k的答案。
我們令count[i] 是二進制數i的1的個數。
valid[i][j] 代表狀態j是否能在第i行出現。
所以狀態轉移方程:
如果valid[i][j]valid[i1][k]j|k==j|l==0 ,那麼有f[i][j][k]=max{f[i1][k][l]}+count[j]
## code

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int num=0;
    char c=' ';
    bool flag=true;
    for(;c>'9'||c<'0';c=getchar())
    if(c=='-')
    flag=false;
    for(;c>='0'&&c<='9';num=num*10+c-48,c=getchar());
    return flag ? num : -num;
}
const int maxn=200;
int n,m,dp[maxn][maxn][maxn];  
int a[maxn];
int top,s[maxn],num[maxn];
void init(){
    n=read();m=read();
    int k=1<<m;
    for(int i=0;i<k;i++)
        if((i&(i<<1))==0&&(i&(i<<2))==0){
            s[top]=i;
            num[top]=0;
            int j=i;
            while(j)
            {
                num[top]+=j%2;
                j/=2;
            }
            top++;
        }
    string s;
    for(int i=0;i<n;i++){
            a[i]=0;
            cin>>s;
            for(int j=0;j<m;j++)
                if (s[j]=='P')
                    a[i]+=1<<j;
        }
}
void one_and_two(){//前兩行的dp值需要預先處理,否則無法轉移。
    for(int j=0;j<top;j++)
        {
            if((s[j]&a[0])!=s[j])
                continue;
            for(int k=0;k<top;k++)
                dp[0][j][k]=num[j];
        }
    if(n>1)
        for(int j=0;j<top;j++)
        {
            if((s[j]&a[1])!=s[j])
                continue;
            for(int k=0;k<top;k++)
            {
                if((s[j]&s[k])==0)
                    dp[1][j][k]=dp[0][k][0]+num[j];
            }
        }
}
void work(){
    for (int i=2;i<n;i++)
        {
            for(int j=0;j<top;j++)
            {
                if((s[j]&a[i])!=s[j])
                    continue;
                for(int k=0;k<top;k++)
                {
                    if(s[j]&s[k])
                        continue;
                    for(int h=0;h<top;h++)
                    {
                        if (s[j]&s[h])
                            continue;
                        dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][h]);
                    }
                    dp[i][j][k]+=num[j];
                }
            }
        }
        int ans=0;
        for(int j=0;j<top;j++)
        {
            for(int k=0;k<top;k++)
                ans=max(ans,dp[n-1][j][k]);
        }
        printf("%d\n",ans);
}
int main(){
    init();
    one_and_two();
    work();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章