BZOJ1087: [SCOI2005]互不侵犯King

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 4772  Solved: 2769
[Submit][Status][Discuss]

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

 

套路,预处理合法状态并标号,state[i]表示标号为i的合法状态,g[i][j]表示标号为i的合法状态与标号为j的合法状态是否可以作为相邻行

dp[i][j][l]表示第i行,前i行有j个国王,第i行状态标号为l

刷表转移即可

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 #include <cmath>
 7 #include <queue>
 8 #include <vector>
 9 #define min(a, b) ((a) < (b) ? (a) : (b))
10 #define max(a, b) ((a) > (b) ? (a) : (b))
11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
12 inline void swap(long long &a, long long &b)
13 {
14     long long tmp = a;a = b;b = tmp;
15 }
16 inline void read(long long &x)
17 {
18     x = 0;char ch = getchar(), c = ch;
19     while(ch < '0' || ch > '9') c = ch, ch = getchar();
20     while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
21     if(c == '-')x = -x;
22 }
23 
24 const long long INF = 0x3f3f3f3f;
25 
26 long long n,k,dp[10][82][1 << 9];
27 //dp[i][j][l]表示第i行放j个国王状态为state[l]的方案数 
28 
29 long long state[1 << 9], tot, g[1 << 9][1 << 9], num[1 << 9];
30 
31 int main()
32 {
33     read(n), read(k);
34     long long ma = 1 << n;
35     for(register long long i = 0;i < ma;++ i)
36         if(!(i & (i << 1)) && !(i & (i >> 1)))
37         {
38             state[++ tot] = i;
39             long long tmp = i;
40             for(;tmp;tmp >>= 1) num[tot] += (tmp & 1);
41         }
42     for(register long long i = 1;i <= tot;++ i)
43         for(register long long j = i;j <= tot;++ j)
44             if(!(state[i] & (state[j] << 1)) && !(state[i] & (state[j] >> 1)) && !(state[i] & state[j]))
45                 g[i][j] = g[j][i] = 1;
46     for(register long long i = 1;i <= tot;++ i) if(num[i] <= k) dp[1][num[i]][i] = 1;
47     for(register long long i = 1;i < n;++ i)
48         for(register long long j = 0;j <= k;++ j)
49             for(register long long l = 1;l <= tot;++ l)
50                 if(num[l] <= j)
51                     for(register long long r = 1;r <= tot;++ r)
52                         if(g[l][r] && j + num[r] <= k)
53                             dp[i + 1][j + num[r]][r] += dp[i][j][l];
54     long long ans = 0;
55     for(register long long i = 1;i <= tot;++ i)
56         ans += dp[n][k][i];
57     printf("%lld", ans);
58     return 0;
59 } 
BZOJ1087

 

posted @ 2018-01-14 11:48  嘒彼小星  阅读(239)  评论(0编辑  收藏  举报