BZOJ1087 互不侵犯 King

题面

在 $N\times N​$ 的棋盘里面放 $K​$ 个国王$(N\leq 9)​$,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共 $8$ 个格子。

题解

就是个简单的状压 $DP$ 题,设状态 $f[i][s][k]$表示dp到第$i$行,这行的状态为$s$,前$i$行共放了$k$个国王的方案数。

每一行从上一行与所枚举状态不冲突的状态转移就行。

假设当前状态为 $s$ ,上一行的 $t$ 状态与它不冲突,那么可以有转移:

$$f[i][s][k]\ \ +=\ \ f[i – 1][t][k – cnt(s)]$$

$cnt(s)$ 表示 $s$ 这个状态中有多少个国王。

我用了滚动数组。

程序

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define MAX_N 527
typedef long long ll;

int N, K;
ll f[2][MAX_N][82];

inline int read () {
    int x = 0;
    char c = getchar();
    while (c < '0' || '9' < c)
        c = getchar();
    while ('0' <= c && c <= '9')
        x = x * 10 + c - '0', c = getchar();
    return x;
}

inline bool check (int x) {
    for (int i = 0;i < N - 1; ++i) {
        if (((x >> i) & 1) & ((x >> i + 1) & 1)) return false;
    }
    return true;
}

inline bool check2 (int x, int y) {
    for (int i = 0;i < N; ++i) {
        if (((x >> i) & 1) & ((y >> i) & 1)) return false;
        if (((x >> i) & 1) & ((y >> i + 1) & 1)) return false;
    }
    for (int i = 0;i < N; ++i) {
        if (((y >> i) & 1) & ((x >> i + 1) & 1)) return false;
    }
    return true;
}

int main () {
    N = read(), K = read();
    int t = 0, tot = (1 << N) - 1, cnt = 0;
    for (int i = 0;i <= tot; ++i)
        if (check(i)) {
            cnt = 0;
            for (int j = 0;j < N; ++j)
                cnt += ((i >> j) & 1);
            f[t][i][cnt] = 1;
        }
    t ^= 1;
    for (int i = 2;i <= N; ++i) {
        for (int j = 0;j <= tot; ++j) {
            if (!check(j)) continue;
            cnt = 0;
            for (int k = 0;k < N; ++k)
                cnt += ((j >> k) & 1);
            for (int k = 0;k <= tot; ++k) {
                if (!check(k)) continue;
                if (!check2(j, k)) continue;
                for (int p = 0;p <= K - cnt; ++p)
                    f[t][j][p + cnt] += f[t ^ 1][k][p];
            }
        }
        t ^= 1;
        memset(f[t], 0, sizeof(f[t]));
    }
    ll res = 0;
    for (int i = 0;i <= tot; ++i)
        res += f[t ^ 1][i][K];
    printf("%lld\n", res);
    return 0;
}

sys_con

OIer,常规 / 竞赛都渣得不行

发表评论

电子邮件地址不会被公开。 必填项已用*标注