原题链接

[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. rust中的ref

    理解Rust的引用与借用(好文链接) #![feature(core_intrinsics)] fn print_type_of<T>(_: T) { println!("{}& ...

  2. python操作ini文件

    简介 ini文件作为常见的配置文件,因此需要对ini文件做处理,此处使用configparser模块,本文介绍以下ini文件常用的处理方式. 需要读取的ini文件 如下文件,[ ]包含的称为secti ...

  3. github访问较慢问题初步解决方案

    简介 众所周知,github在国内向来都是访问的非常坎坷,不挂代理访问起来非常困难,本文将介绍一种不依赖代理的加快访问的方式,但不一定可行哦,只能说是优化 步骤 1.在搜索框中输入记事本或者notep ...

  4. 还在用Alpine作为你Docker的Python开发基础镜像?其实Ubuntu更好一点

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_173 一般情况下,当你想为你的Python开发环境选择一个基础镜像时,大多数人都会选择Alpine,为什么?因为它太小了,仅仅只有 ...

  5. devops-1:代码仓库git的使用

    devops-gitlab 介绍 gitlab同github.gitee和bitbucket功能一致,都是提供一个存储代码的服务,这里就以gitlab为例,学习一下如何结合git工具使用. 核心组件: ...

  6. win10下计算文件哈希值的方法

    cmd下使用certutil命令 使用方法: certutil -hashfile FILE_NAME ALGORITHM_NAME 支持的加密算法包括:MD2,MD4,MD5,SHA1,SHA256 ...

  7. java-异步与并发之基础

    1.线程提供了一个方法: void join()该方法允许一个线程在另一个线程上等待,直到其完成工作后才解除阻塞运行.所以join可以协调线程之间同步运行线程调用join()方法,方法后就进入阻塞状态 ...

  8. Postman中的断言

    Postman设置断言 一.断言的定义 1.什么是断言? 一般一个完整的接口测试,包括:请求->获取响应正文->断言,请求和获取响应正文很常见.断言一般是对请求的响应结果做操作,判断预期结 ...

  9. Atcoder Beginner Contest 200 E. Minflip Summation(概率数论)

    题面 一个字符串 T T T 是由一个包含 0.1.? 的字符串 S S S 循环连接 K K K 次获得的. 字符串 T T T 中的每个 ? 都可以换成 0 或 1 ,假设 T T T 中一共有 ...

  10. javaee相关基础

    2020-2-28 java 学习 开始学习javaee了 瞎跳着看 今日内容 web相关概念 web服务器软件:Tomcat Servlet入门学习 web概念 软件架构 C/S:客户端/服务器端 ...