[Luogu P1896] [BZOJ 1087] [SCOI2005]互不侵犯

本文介绍了一种使用状态压缩动态规划(状压DP)的方法来解决在N×N的棋盘中放置K个国王,使它们互不攻击的问题。通过预处理每行的合法状态,利用状态压缩进行快速转移,实现高效求解方案数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

洛谷传送门
BZOJ传送门

题目描述

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

输入输出格式

输入格式:

只有一行,包含两个数 N N N K K K 1 ≤ N ≤ 9 , 0 ≤ K ≤ N ∗ N 1 \le N \le 9, 0 \le K \le N * N 1N9,0KNN

输出格式:

所得的方案数

输入输出样例

输入样例#1:
3 2
输出样例#1:
16

解题分析

状压每一行的状态并枚举上一行的状态进行转移, 因为每行单独的合法状态其实个数很少, 可以先预处理出来进行转移。

代码如下:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <cctype>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
ll dp[10][512][512];
int cnt[512], n, lim, tot, stat[512];
void pre()
{
    int bd = (1 << n) - 1;
    for (R int i = 0; i <= bd; ++i)
    {
        if(i & (i << 1) || (i & (i >> 1))) continue;
        stat[++tot] = i; cnt[tot] = __builtin_popcount(i);
        dp[1][cnt[tot]][tot] = 1;
    }
}
int main(void)
{
    scanf("%d%d", &n, &lim);
    pre(); R int i, j, k, tar, bd, o;
    for (i = 2; i <= n; ++i)
    {
        for (j = 0; j <= lim; ++j)
        {
            for (k = 1; k <= tot; ++k)
            {
                tar = j - cnt[k];
                if(tar < 0) continue;
                for (o = 1; o <= tot; ++o)
                {
                    if((!(stat[o] & stat[k])) && (!(stat[o] & (stat[k] << 1))) && (!(stat[o] & (stat[k] >> 1))))
                    dp[i][j][k] += dp[i - 1][j - cnt[k]][o];
                }
            }
        }
    }
    ll ans = 0;
    for (R int i = 1; i <= tot; ++i) ans += dp[n][lim][i];
    printf("%lld", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值