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\n",ans);
    return 0;
}

题外话:

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

只要努力就能克服困难!

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

时间: 2024-11-05 16:24:24

Luogu P1896 [SCOI2005]互不侵犯的相关文章

洛谷 P1896 [SCOI2005]互不侵犯King

题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入输出格式 输入格式: 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) 输出格式: 所得的方案数 输入输出样例 输入样例#1: 3 2 输出样例#1: 16 #include<cstdio> #include<cstring> #include<ios

P1896 [SCOI2005]互不侵犯King

题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入输出格式 输入格式: 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) 输出格式: 所得的方案数 输入输出样例 输入样例#1: 3 2 输出样例#1: 16 题解:状态压缩动规,用一个整型的二进制表示来表示棋盘上一行的情况,放了棋子为1,没放为0:可以先预处理出所有可能的状态:用位

#(状压DP)P1896 [SCOI2005]互不侵犯(提高+/省选-)

题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 注:数据有加强(2018/4/25) 输入格式 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) 输出格式 所得的方案数 输入输出样例 输入 #1复制 3 2 输出 #1复制 16 #include<cstdio>#include<iostream>using

P1896 [SCOI2005]互不侵犯

______________________________________________________________ 和上一题差不多,注意初始化与判断即可 #include<bits/stdc++.h> using namespace std; long long int n,kk,tot,can[4096],dp[11][1096][121],cnt[4096]; long long ans; int main() { cin>>n>>kk; for(int

1896 [SCOI2005]互不侵犯 状压dp

传送门 这是一道状压dp的经典例题 题目让输出所有可能的方案数 很显然 这是一道动态规划了 由于国王放置的位置有一定的限制 所以我们要在状态转移的过程中增加一维来存储状态 我们这一道题假设f[i][j][k] 意思是在前i行一共放置了j个国王 第i行国王放置的状态是k  存储的值是方案数 首先 我们可以先预处理出左右合法的每行的状态...(有点绕 就是说针对单独的一行 会有那些合法的状态 使得相邻的两个格子最多只能放置一个国王 没有相邻的国王 然后我们开始dp 我们分别枚举i k s i是当前枚

[SCOI2005]互不侵犯King

1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4255  Solved: 2458 [Submit][Status][Discuss] Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上 左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <=

BZOJ 1087: [SCOI2005]互不侵犯King( 状压dp )

简单的状压dp... dp( x , h , s ) 表示当前第 x 行 , 用了 h 个 king , 当前行的状态为 s . 考虑转移 : dp( x , h , s ) = ∑ dp( x - 1 , h - cnt_1( s ) , s' ) ( s and s' 两行不冲突 , cnt_1( s ) 表示 s 状态用了多少个 king ) 我有各种预处理所以 code 的方程和这有点不一样 ------------------------------------------------

BZOJ1087:[SCOI2005]互不侵犯King(状压DP)

[SCOI2005]互不侵犯King Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Output 方案数. Sample Input 3 2 Sample Output 16 分析: 经典的状压DP题目,可我竟然调了很长时间都没对,后来发现是DP枚举范围错

BZOJ1087=Codevs2451=洛谷P1896&amp;P2326互不侵犯

1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2885  Solved: 1693[Submit][Status][Discuss] Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K &