原题链接

[SCOI2005] 互不侵犯

题目描述

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

注:数据有加强(2018/4/25)

输入格式

只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

输出格式

所得的方案数

样例 #1

样例输入 #1

3 2

样例输出 #1

16

审题

由题目可得:棋盘上国王割据的过程是随着“阶段”的增长,在每个状态维度上不断扩展的。在任意时刻,已经求出最优解的状态与尚未求出最优解的状态在各维度上的分界点组成了DP扩展的“轮廓”。而在这道题中,我们需要经济地保存棋盘的详细状态,所以想到状态压缩DP。

状态压缩DP介绍

以本题为例,假如有一行的国王放置状态如下

这里使用两个数组记录状态

sit[i]表示有无国王的二进制状态

sta[i]表示国王的个数

则如上图\(sit[i]=(100101)_2=37\),\(sta[i]=3\).

这样一来,一行中国王的状态就被压缩到一个维度中

推导转移方程

\(f[i][j][s]+=f[i-1][k][s-sta[j]]\)

其中,i表示第i行,j表示当前国王状态,s表示当前国王个数,结合sit[],sta[]表示。

预处理每一个状态

dfs(x,num,cur)元素含义:x表示递归的层数,num表示已经上场的国王数量,cur表示当前遍历到的位置(行)

点击查看代码
void dfs(int x,int num,int cur)//预处理每一个状态
{
if(cur>=n)//超出边界,处理完毕
{
sit[++cnt]=x;
sta[cnt]=num;
return ;
}
dfs(x,num,cur+1);//当前位置不放国王:国王数量不变,下一个位置可以放国王,故指向下一个位置
dfs(x+(1<<cur),num+1,cur+2);//当前位置放国王:国王数量+1,下一个位置不可以放国王,故指向下下个位置
}

判断冲突情况

知识点:位运算

点击查看代码
if(sit[j]&sit[x]) continue;//x:当前行位置国王放置情况;j:正上方位置国王放置情况。上下冲突
if((sit[j]<<1)&sit[x]) continue;//左上右下冲突
if(sit[j]&(sit[x]<<1)) continue;//右上左下冲突

以下为图示

程序大致框架:

输入->预处理->DP循环(判断冲突)->统计答案->输出。

完整带注释代码

点击查看代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
int sit[2000],sta[2000];
//sit[i]表示有无国王的二进制状态
//sta[i]表示国王的个数
int cnt=0;
int n,k;
long long f[10][2000][100]={0};
//dfs(x,num,cur)元素含义:x 递归的层数;num 已经上场的国王数量;cur当前遍历到的位置(行)
void dfs(int x,int num,int cur)//预处理每一个状态
{
if(cur>=n)//超出边界,处理完毕
{
sit[++cnt]=x;
sta[cnt]=num;
return ;
}
dfs(x,num,cur+1);//当前位置不放国王:国王数量不变,下一个位置可以放国王,故指向下一个位置
dfs(x+(1<<cur),num+1,cur+2);//当前位置放国王:国王数量+1,下一个位置不可以放国王,故指向下下个位置
}
//f[i][j][s]+=f[i-1][k][s-sta[j]]状态转移方程
//i=第i行;j=当前国王的状态;s=当前国王的个数,可以用sit[]sta[]表示 int main()
{
scanf("%d%d",&n,&k);
dfs(0,0,0);//预处理
for(int i=1;i<=cnt;i++)f[1][i][sta[i]]=1;//处理第一行:防止越界
for(int i=2;i<=n;i++)
for(int j=1;j<=cnt;j++)
for(int x=1;x<=cnt;x++)//x为j正下方的位置
{
if(sit[j]&sit[x]) continue;//x:当前行位置国王放置情况;j:正上方位置国王放置情况。上下冲突
if((sit[j]<<1)&sit[x]) continue;//左上右下冲突
if(sit[j]&(sit[x]<<1)) continue;//右上左下冲突
for(int s=sta[j];s<=k;s++)f[i][j][s]+=f[i-1][x][s-sta[j]];
}
long long ans=0;
for(int i=1;i<=cnt;i++)ans+=f[n][i][k];//n行矩阵,放置k个国王的情况总数
printf("%lld",ans);
return 0;
}

这个视频给我的理解带来极大的帮助

(而且声音很甜很好听)

https://www.bilibili.com/video/av681073078/?vd_source=b9e2e351c4ebc946cfd86808c70b65ce

P1896 [SCOI2005] 互不侵犯 方法记录的更多相关文章

  1. 洛谷 P1896 [SCOI2005]互不侵犯

    洛谷 P1896 [SCOI2005]互不侵犯 题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8 ...

  2. 洛谷P1896 [SCOI2005]互不侵犯King

    P1896 [SCOI2005]互不侵犯King 题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共 ...

  3. 洛谷——P1896 [SCOI2005]互不侵犯

    P1896 [SCOI2005]互不侵犯 状压DP入门题 状压DP一般需要与处理状态是否合法,节省时间 设定状态dp[i][j][k]表示第i行第j个状态选择国王数为k的方案数 $dp[i][j][n ...

  4. 洛谷 P1896 [SCOI2005]互不侵犯 (状态压缩DP)

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 注:数据有加强(2018/4/25) ...

  5. 洛谷 P1896 [SCOI2005]互不侵犯King

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入输出格式 输入格式: 只有一行,包 ...

  6. P1896 [SCOI2005]互不侵犯King

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入输出格式 输入格式: 只有一行,包 ...

  7. 洛谷P1896 [SCOI2005]互不侵犯King【状压DP】

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入格式: 只有一行,包含两个数N,K ...

  8. P1896 [SCOI2005]互不侵犯

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 注:数据有加强(2018/4/25) ...

  9. 【题解】洛谷P1896 [SCOI2005] 互不侵犯(状压DP)

    洛谷P1896:https://www.luogu.org/problemnew/show/P1896 前言 这是一道状压DP的经典题 原来已经做过了 但是快要NOIP 复习一波 关于一些位运算的知识 ...

随机推荐

  1. SQL 字符串去除空格函数汇总

    SQL 中使用ltrim()去除左边空格 ,rtrim()去除右边空格 ,没有同时去除左右空格的函数,要去除所有空格可以用replace(字符串,' ',''),将字符串里的空格替换为空 . 例:去除 ...

  2. Docker 11 自定义镜像

    参考源 https://www.bilibili.com/video/BV1og4y1q7M4?spm_id_from=333.999.0.0 https://www.bilibili.com/vid ...

  3. MyBatis 04 实战

    增删改查实现 在实际使用中,MyBatis 的使用遵从一定的规范. 常用的增删改查的 MyBatis 实现如下: Mapper.xml <?xml version="1.0" ...

  4. 一文带你弄懂 JVM 三色标记算法!

    大家好,我是树哥. 最近和一个朋友聊天,他问了我 JVM 的三色标记算法.我脑袋一愣发现竟然完全不知道!于是我带着疑问去网上看了几天的资料,终于搞清楚啥事三色标记算法,它是用来干嘛的,以及它和 CMS ...

  5. 历时2月,动态线程池 DynamicTp 发布里程碑版本 V1.0.8

    关于 DynamicTp DynamicTp 是一个基于配置中心实现的轻量级动态线程池管理工具,主要功能可以总结为动态调参.通知报警.运行监控.三方包线程池管理等几大类. 经过多个版本迭代,目前最新版 ...

  6. [java]基础学习HELLOWORLD系列

    (一)手把手教你做JDK环境变量配置 步骤 1 : 首先看配置成功后的效果 点WIN键->运行(或者使用win+r) 输入cmd命令 输入java -version 注: -version是小写 ...

  7. 什么?WPF 不支持 SVG ?

    什么?WPF 不支持 SVG ? 控件名:SharpVectors 作者:Elinam LLC (Japan) 项目地址: https://github.com/ElinamLLC/SharpVect ...

  8. ARC120F Wine Thief (组合数学)

    题面 有一个长为 N N N 的序列,相邻的两个数中只能选一个,总共选 k k k 个数,一种方案的价值为选的 k k k 个数的和,问所有合法方案的价值总和,答案对 998244353 取模. 1 ...

  9. 二 代理模式【Proxy Pattern】 来自CBF4LIFE 的设计模式

    什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被代理的人能干活呀. ...

  10. django_day10_项目相关

    django_day10_项目相关 展示数据的方法 数据对象obj 普通字段 obj.字段名 ====> 数据库该字段的值 带choices参数的 obj.字段名 ====> 数据库该字段 ...