原题链接

[SCOI2005] 互不侵犯

题目描述

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

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

输入格式

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

输出格式

所得的方案数

样例 #1

样例输入 #1

  1. 3 2

样例输出 #1

  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表示当前遍历到的位置(行)

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

判断冲突情况

知识点:位运算

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

以下为图示

程序大致框架:

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

完整带注释代码

点击查看代码
  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<string>
  6. #include<algorithm>
  7. using namespace std;
  8. int sit[2000],sta[2000];
  9. //sit[i]表示有无国王的二进制状态
  10. //sta[i]表示国王的个数
  11. int cnt=0;
  12. int n,k;
  13. long long f[10][2000][100]={0};
  14. //dfs(x,num,cur)元素含义:x 递归的层数;num 已经上场的国王数量;cur当前遍历到的位置(行)
  15. void dfs(int x,int num,int cur)//预处理每一个状态
  16. {
  17. if(cur>=n)//超出边界,处理完毕
  18. {
  19. sit[++cnt]=x;
  20. sta[cnt]=num;
  21. return ;
  22. }
  23. dfs(x,num,cur+1);//当前位置不放国王:国王数量不变,下一个位置可以放国王,故指向下一个位置
  24. dfs(x+(1<<cur),num+1,cur+2);//当前位置放国王:国王数量+1,下一个位置不可以放国王,故指向下下个位置
  25. }
  26. //f[i][j][s]+=f[i-1][k][s-sta[j]]状态转移方程
  27. //i=第i行;j=当前国王的状态;s=当前国王的个数,可以用sit[]sta[]表示
  28. int main()
  29. {
  30. scanf("%d%d",&n,&k);
  31. dfs(0,0,0);//预处理
  32. for(int i=1;i<=cnt;i++)f[1][i][sta[i]]=1;//处理第一行:防止越界
  33. for(int i=2;i<=n;i++)
  34. for(int j=1;j<=cnt;j++)
  35. for(int x=1;x<=cnt;x++)//x为j正下方的位置
  36. {
  37. if(sit[j]&sit[x]) continue;//x:当前行位置国王放置情况;j:正上方位置国王放置情况。上下冲突
  38. if((sit[j]<<1)&sit[x]) continue;//左上右下冲突
  39. if(sit[j]&(sit[x]<<1)) continue;//右上左下冲突
  40. for(int s=sta[j];s<=k;s++)f[i][j][s]+=f[i-1][x][s-sta[j]];
  41. }
  42. long long ans=0;
  43. for(int i=1;i<=cnt;i++)ans+=f[n][i][k];//n行矩阵,放置k个国王的情况总数
  44. printf("%lld",ans);
  45. return 0;
  46. }

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

(而且声音很甜很好听)

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. Class对象共嫩

    需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法 实现: 1.配置文件 2.反射 步骤: 1.将需要创建的对象的全类名和需要执 ...

  2. Vxe-table 高亮当前行

    需求 1 :设置初始高亮 子组件: 父组件 需求 2 :高亮行的变化,需要把数据传递到兄弟组件中 解决办法:EventBus 参考链接: http://t.csdn.cn/iwOJc main.js ...

  3. Javascript 构造函数、原型对象、实例之间的关系

    # Javascript 构造函数.原型对象.实例之间的关系 # 创建对象的方式 # 1.new object() 缺点:创建多个对象困难 var hero = new Object(); // 空对 ...

  4. Luogu1063 能量项链 (区间DP)

    惊恐地发现自己连区间DP都会错2333 #include <iostream> #include <cstdio> #include <cstring> #incl ...

  5. Spring 03 切面编程

    简介 AOP(Aspect Oriented Programming),即面向切面编程 这是对面向对象思想的一种补充. 面向切面编程,就是在程序运行时,不改变程序源码的情况下,动态的增强方法的功能. ...

  6. java学习第一天.day05

    jvm的内存 栈:类方法使用后自动销毁,销毁的好处是释放内存 java方法执行时,在栈区执行 堆: 线程共享的一块内存区域      所有的对象实例以及 数组 都要在堆上分配      每次使用new ...

  7. 经典设计原则 - SOLID

    SOLID 设计原则包含以下 5 种原则: 单一职责原则(Single Responsibility Principle, SRP) 开闭原则(Open Closed Principle, OCP) ...

  8. PerfView专题 (第八篇):洞察 C# 内存泄漏之寻找静态变量名和GC模式

    一:背景 这篇我们来聊一下 PerfView 在协助 WinDbg 分析 Dump 过程中的两个超实用技巧,可能会帮助我们快速定位最后的问题,主要有如下两块: 洞察内存泄漏中的静态大集合变量名. 验证 ...

  9. n【c#】委托:delegate 学习笔记

    类似于c/c++的指针,只不过c#的委托存储的是某个方法的调用,派生子System.Delegate

  10. 第八十篇:Vue购物车(一) 购物车基本框架

    好家伙,又是购物车 来吧,这是参照黑马的课程写的一个购物车 目录结构如下: 1.首先组件导入, Counter.vue <template> <div class="num ...