文章標題 POJ 1185 : 炮兵陣地 (狀壓DP)

題目鏈接

分析:首先我們可以先預處理一行中出所有狀態中哪那些狀態是可行的,即炮兵不會被放在另一個炮兵的射程內用each數組存儲。然後同樣預處理出地圖每一行的狀態,其中高地用1表示,用mp數組存儲,這兩個數組是我爲了判斷在第j行中第i個狀態是否可行,即each[i]&mp[j],返回1表示有 衝突
然後我們用dp[I][j][k]來表示在第i行中的第j個狀態與第n-1行中的第k個狀態中炮兵的數量,然後預處理出第1,2行,然後就可以寫出狀態轉移方程了
dp[I][j][k]=max(dp[I-1][k][kk])其中j表示第I行的狀態,k表示第i-1行的狀態,kk表示第i-2行的狀態,且這三行中的狀態與地圖沒有衝突,兩兩對應的狀態也沒有衝突。
代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
typedef long long ll;

const int mod=1e9+7;
const int maxn=1e5+10;

char ch[105][15];
ll dp[105][65][65];
int each[65];//each[i]表示每一行中合理的不產生衝突的狀態
int sum[65];//表示第i種狀態中炮兵(即1)的數量 
int mp[105];//表示每一行中地圖的狀態,高地(H)爲1 
int n,m;

bool judge(int s){//判斷s這個狀態是否符合題意(即不互相攻擊) 
    for (int i=0;i<m;){
        if (s&(1<<i)){
            if (i+1<m&&(s&(1<<(i+1))))return false;
            if (i+2<m&&(s&(1<<(i+2))))return false;
            i+=2; 
        }else i++;
    }
    return true;
}

bool judge_map(int row,int s){//s這個狀態在第row行是否可行,返回1表示不可行,因爲炮兵放在高地了 
    return (mp[row]&s); 
}

int main()
{
    while (scanf ("%d%d",&n,&m)!=EOF){
        for (int i=1;i<=n;i++){
            scanf ("%s",ch[i]+1);
            mp[i]=0;
            for (int j=1;j<=m;j++){
                if (ch[i][j]=='H'){
                    mp[i]+=(1<<(j-1));
                }
            } 
        }
        memset (dp,0,sizeof (dp));
        int cnt=0;
        for (int i=0;i<(1<<m);i++){//預處理出每一行可行的狀態數 
            if (judge(i))each[cnt++]=i;
        }
        for(int i=0;i<cnt;i++){//與處理出每一種狀態的炮兵數 
            sum[i]=0;
            for (int j=0;j<m;j++){
                if (each[i]&(1<<j)){
                    sum[i]++;
                }
            }
        } 
        for(int i=0;i<cnt;i++){//預處理第一行 
            if (!judge_map(1,each[i])){
                dp[1][i][0]=sum[i];
            }
        } 
        for(int i=0;i<cnt;i++){//第二行 
            if (judge_map(2,each[i]))continue;
            for (int j=0;j<cnt;j++){
                if (!(each[i]&each[j])){//這兩行對應的狀態沒有衝突 
                    dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+sum[i]);
                }
            }
        } 

        for (int i=3;i<=n;i++){
            for (int j=0;j<cnt;j++){//第i行的狀態 
                if (judge_map(i,each[j]))continue;
                for (int k=0;k<cnt;k++){//第n-1行的狀態 
                    if (judge_map(i-1,each[k])) continue;
                    if ((each[j]&each[k]))continue;//i行與 i-1行衝突
                    for (int kk=0;kk<cnt;kk++){//第n-2行的狀態 
                        if (judge_map(i-2,each[kk]))continue;
                        if (each[k]&each[kk])continue;//i-1行與i-2衝突
                        if (each[j]&each[kk])continue;//i行與i-2行衝突
                        dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][kk]+sum[j]); 
                    } 
                }
            }
        } 
        ll ans=0;
        for (int i=0;i<cnt;i++){
            for (int j=0;j<cnt;j++){
                ans=max(ans,dp[n][i][j]);
            }
        } 
        printf ("%lld\n",ans);
    }
    return 0;
}
發佈了191 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章