Luogu P1896 [SCOI2005]互不侵犯

gate

第二道状压dp...

预处理每种状态j所含1的个数为sum[j]

f[i][j][l]代表第i行,状态为j,当前共有l个国王

枚举本层状态j,上一层状态k,判断八方向是否有相邻:k&j||(k<<1)&j||(k>>1)&j

枚举国王数l,则有f[i][j][l] += f[i-1][k][l-sum[j]]

最后统计f[n][ ][m]即为答案

代码如下

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
using namespace std;

const int mod = 1e9;

int n,m;
long long ans;
int a[10],sum[1<<9+5],g[1<<9+5];
long long f[10][1<<9+5][100];

int main() {
    scanf("%d%d",&n,&m);
    
    for(int i = 0; i < (1<<n); i++) {
        g[i] = (!((i<<1)&i) && !((i>>1)&i));
        for(int j = 0; (1<<j) <= i; j++)
            if((1<<j)&i) sum[i]++;
        if(g[i]) f[1][i][sum[i]] = 1;
    }
    for(int i = 2; i <= n; i++)
        for(int j = 0; j < (1<<n); j++) {
            if(!g[j]) continue;
            for(int k = 0; k < (1<<n); k++) {
                if(k&j||(k<<1)&j||(k>>1)&j) continue;
                for(int l = 0; l <= m; l++)
                    f[i][j][l] += f[i-1][k][l-sum[j]];
            }
        }

    for(int i = 0; i < (1<<n); i++)
        ans += f[n][i][m];
    printf("%lld
",ans);
    return 0;
}
View Code

题外话:

以前总觉得状压dp很难,一直不想写这个东西。写了才发现其实没什么...

只要努力就能克服困难!

原文地址:https://www.cnblogs.com/mogeko/p/11625775.html