洛谷1377 M国王 (SCOI2005互不侵犯King)

本题地址:http://www.luogu.org/problem/show?pid=1377

题目描述

天天都是n皇后,多么无聊啊。我们来一道m国王游戏吧!
   题目是这样的,在n*n的格子里放m个国王,使他们不互相攻击,有多少种放法呢?(可以为0)
   国王的攻击力大不如皇后,他只能对与他相邻的8个格子产生攻击。

输入输出格式

输入格式:

n,m

输出格式:

方案数

输入输出样例

输入样例#1:

1 1

输出样例#1:

1

说明

数据范围:
100%的数据满足n<=8,m<=n*n
时限2秒(保证正常代码可以在时限内通过)

【思路】

状态压缩DP。

注意这个题与n皇后的差别:可以有多个国王放在同一行。

设d[i][s1][j]表示放到第i行 第i行放置状态为s1 且已经放了j个 的方案数。s用二进制表示。则有转移方程如下:

d[i][s1][j]
+= d[i-1][s2][j-cnt[s1]]

其中cnt表示状态中放置的国王数。

优化:注意到不是每一个状态都是有用的,也不是任两个状态可以互相转移。因此可以提前筛去自身不符合要求的状态(can),同时建立状态之间的边(has_edge)。

 

【代码】

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4
 5 const int maxn = 1<<9;
 6
 7 typedef long long LL;
 8 LL d[9][maxn][9*9];
 9 int cnt[maxn];
10 bool has_edge[maxn][maxn];
11 bool can[maxn];
12 int n,m,all;
13
14 void get_edge() {
15     for(int i=0;i<all;i++) if((i&i>>1)==0)
16     {
17        can[i]=true;
18        for(int j=0;j<n;j++) if(i&(1<<j)) cnt[i]++;
19        for(int j=0;j<all;j++)
20           if(((i&j)==0) && ((i>>1)&j)==0 && ((j>>1)&i)==0)
21              has_edge[i][j]=true;
22     }
23 }
24
25 int main() {
26     cin>>n>>m;
27     all=1<<n;
28
29     get_edge();
30     for(int s=0;s<all;s++) if(can[s]) d[1][s][cnt[s]]=1;
31
32     for(int i=2;i<=n;i++)
33        for(int s1=0;s1<all;s1++) if(can[s1])
34           for(int j=cnt[s1];j<=m;j++)
35           {
36              for(int s2=0;s2<all;s2++) if(can[s2] && has_edge[s1][s2])
37                 d[i][s1][j] += d[i-1][s2][j-cnt[s1]];
38           }
39     LL ans=0;
40     for(int s=0;s<all;s++)  ans += d[n][s][m];
41     cout<<ans;
42     return 0;
43 }

另外一定要注意二进制的运算优先级,不确定的时候就加括号。

时间: 2024-11-05 13:48:28

洛谷1377 M国王 (SCOI2005互不侵犯King)的相关文章

[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枚举范围错

SCOI2005互不侵犯King

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

[Bzoj1083][SCOI2005]互不侵犯king(状压dp)

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

洛谷 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

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

Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Output 方案数. Sample Input 3 2 Sample Output 16 HINT Source Solution 状压$dp$就是把状态压缩成二进制数,利用二进制的位运算改进算法的一种方法

【BZOJ 1087】[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 同学很早之前打表过了,orz 这题正解状压DP,f[i][s][k]表示第i行上一行的状态为S,选了k个 预处理出所有

[BZOJ1087][SCOI2005]互不侵犯King解题报告|状压DP

在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 好像若干月前非常Naive地去写过DFS... 然后其实作为状压DP是一道非常好的题啦>< 感觉直接无脑搞时间是下不来的 做了好几道预处理 使得最后DP的过程中没有任何一条转移是无用的 1 program bzoj1087; 2 var i,x,n,k,j,p,q,t1,t2:longint; 3 ans:int64; 4 a:array[-1