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;
}

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