P2704 [NOI2001]炮兵陣地---狀壓DP

https://www.luogu.org/problemnew/show/P2704

這道題較前面玉米地的題稍微升級了一些,影響範圍擴大到2行內

狀壓DP前面做的工作還是相同的,預處理狀態

因爲這題n比較大 所以我們直接把合適的狀態存起來  後面再用就只循環合法的狀態了  不然會爆掉

dp[i][j][k] 三維狀態分別表示 第i行的j狀態它上一行爲k狀態時的最大方案數

轉移:dp[i][j][h] = max(dp[i][j][h],dp[i-1][h][k] + num[j]);

先預處理1,2行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 100;
const int M = 1e7 + 100;
const int INF = 0x3f3f3f3f;
const int mod = 100000000;
ll a[105][15],n,m,s[(1<<10)+100],dp[110][(1<<10)+100][(1<<10)+100];
vector<int> v,num;
bool ok[105][(1<<10)+100];
int main()
{
    cin >> n >> m;
    char c;
    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= m;j ++){
            cin >> c;
            if(c == 'P') a[i][j] = 1;
        }
    //壓縮地圖
    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= m;j ++)
            s[i] = (s[i]<<1) + a[i][j];
    //預處理狀態
    for(int i = 0;i < (1<<m);i ++){
        if(((i<<1)&i) == 0 && ((i<<2)&i) == 0){
            v.push_back(i);
            int tmp = i;
            int cnt = 0;
            while(tmp){
                if(tmp&1) cnt ++;
                tmp >>= 1;
            }
            num.push_back(cnt);
        }
    }
    //預處理第一行
    for(int i = 0;i < v.size();i ++){
        if((v[i]&s[1]) == v[i]){
            ok[1][i] = true;
            dp[1][i][0] += num[i];
        }
    }
    //預處理第二行
    for(int i = 0;i < v.size();i ++){
        if((v[i]&s[2]) == v[i]){
            ok[2][i] = true;
            for(int j = 0;j < v.size();j ++){
                if(ok[1][j] && (v[i]&v[j]) == 0){
                    dp[2][i][j] = max(dp[2][i][j],dp[1][j][0] + num[i]);
                }
            }
        }
    }
    for(int i = 3;i <= n;i ++){
        for(int j = 0;j < v.size();j ++){
            if((v[j]&s[i]) == v[j]){
                ok[i][j] = true;
                for(int k = 0;k < v.size();k ++){
                    if(ok[i-2][k] && (v[j]&v[k]) == 0){
                        for(int h = 0;h < v.size();h ++){
                            if(ok[i-1][h] && (v[h]&v[k]) == 0 && (v[j]&v[h]) == 0){
                                dp[i][j][h] = max(dp[i][j][h],dp[i-1][h][k] + num[j]);
                            }
                        }
                    }
                }
            }
        }
    }
    ll ans = 0;
    for(int i = 0;i < v.size();i ++){
        for(int j = 0;j < v.size();j ++){
            ans = max(ans,dp[n][i][j]);
        }
    }
    cout << ans;
    return 0;
}

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