互不侵犯KING

题意:

给一个$n * m$大小的地图, H表示山地,P代表平原,你可以在平原上部署一支炮兵部队,他们的攻击距离如图所示

让你求最多可以部署多少支部队,使得任意两支部队之间无法互相攻击

思路:

状态压缩DP,我们把每一行的状态用二进制来表示,山地为1,平原为0;然后我们枚举每一行的状态,把符合左右两格互不影响的所有状态存入$st$数组当中,这一状态S中的炮兵的数量我们用num[cnt]=__builtin_popcount(s);找出其中的1的个数即是。然后我们逐行遍历,枚举所有状态,合理的就计算

状态设置:

我们设置$ f[i][j][k]$ 表示我们枚举到i行,j表示这一行的状态,k表示上一行的状态,这时的炮兵的最大数量即是属性

转移方程:

我们处理这一行时,首先要判断枚举到的某个状态是否在山上,如果没有山地,那么枚举上一行的状态,如果不在山地,且不与本行冲突,那么枚举上两行的状态,如果不在山上,且不与本行冲突,不与上一行冲突,那么就可以进行状态转移。


$f[i][j][k]=max(f[i][j][k],f[i-1][k][p]+num[j])$

初始化细节提示:

初始化时,我们首先要存所有满足条件的状态的炮兵的数量,以及满足条件的状态,然后我们预处理第二行即可。

代码:

/*
__builtin_popcount = int
__builtin_popcountl = long int
__builtin_popcountll = long long
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod= 998244353;
int n,m,f[110][1ll<<10][1ll<<10],cnt,st[1ll<<10],num[1ll<<10],ans;
int a[110];
void init(){
    for (int s = 0; s <(1ll<<m) ; ++s) {
        if(!(s&(s<<1ll))&&!(s&(s<<2ll))){
            st[++cnt]=s;
            num[cnt]=__builtin_popcount(s);
        }
    }
}
void solve(){
    cin>>n>>m;
    for (int i = 1; i <=n ; ++i) {
        for (int j = 1; j <=m ; ++j) {
                char s;
                cin>>s;
                if(s=='H')a[i]+=1ll<<(j-1);
        }
    }
    init();
    for (int i = 1; i <=cnt ; ++i) {
        for (int j = 1; j <=cnt ; ++j) {
            if(!(st[i]&st[j])&&!(st[i]&a[2])&&!(st[j]&a[1])){
                f[2][i][j]=num[i]+num[j];
            }
        }
    }
    ///f[i][j][k]表示第i行成立时,上一行是j状态,上两行是k状态的方案数。
    for (int i = 3; i <=n ; ++i) {
        for (int j = 1; j <=cnt ; ++j) {
            if(!(st[j]&a[i])){
                for (int lfirst = 1; lfirst <=cnt ; ++lfirst) {
                    if(!(st[lfirst]&a[i-1])&&!(st[lfirst]&st[j])){
                        for (int lsecond = 1; lsecond <=cnt ; ++lsecond) {
                            if(!(st[lsecond]&a[i-2])&&!(st[lsecond]&st[lfirst])&&!(st[lsecond]&st[j])){
                                f[i][j][lfirst]=max(f[i][j][lfirst],f[i-1][lfirst][lsecond]+num[j]);
                                ans= max(ans,f[i][j][lfirst]);
                            }
                        }
                    }
                }
            }
        }
    }
    cout<<ans<<'\n';

}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t=1;
    //cin>>t;
    while (t--)solve();

}
posted on 2023-08-01 10:06  IR101  阅读(14)  评论(0编辑  收藏  举报  来源