Problem Specification | Value |
---|---|
Time Limit | 10 Sec |
Memory Limit | 162 MB |
Submit | 2697 |
Solved | 1588 |
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
状压 DP, 将每一个列存上所有国王的位置, true or false, 然后推断下一行, 注意不要溢出.
话说把这个写成 class 实在是太累......
#include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;
typedef long long lli;
const int maxn = 10, maxm = 90, maxk = 512;
int n, K;
lli dp[maxn][maxm][maxk];
bool dp_ok[maxk][maxk], dp_ok_2d[maxk];
#define states(__x) (1 << (__x))
#define get_pos(__st, __dig) (((__st) >> ((__dig) - 1)) & 1)
int get_digs(int __st) { int res=0;for(int i=1;i<=16;i++)res+=(int)(get_pos(__st,i));return res; }
// This function preprocesses the required dp data.
// dp_ok[x][y] Whether state x is safe as a previous row for state y.
void preprocess_dp(void)
{
// Current row is of state i.
for (int i = 0; i < states(n); i++) {
// Whether this is safe for itself, i.e. do not contradict adjacence
// by itself on the same row.
bool ok = true;
for (int j = 2; j <= n; j++)
if (get_pos(i, j) && get_pos(i, j - 1))
ok = false;
dp_ok_2d[i] = ok; // Whether this is legal on this position
if (!ok)
continue;
// Previous row is of state j.
for (int j = 0; j <= i; j++) {
bool res = true;
for (int k = 1; k <= n; k++)
if (get_pos(i, k)) {
// Avoid segmentation violation
if (k > 1 && get_pos(j, k - 1)) res = false;
if (get_pos(j, k)) res = false;
if (k < n && get_pos(j, k + 1)) res = false;
}
dp_ok[i][j] = dp_ok[j][i] = res;
}
}
return ;
}
int main(int argc, char** argv)
{
// dp[i][j][k]: row #i, placed j kings, status of all columns = bin(k)
scanf("%d%d", &n, &K);
// Preprocess dp availability
preprocess_dp();
// Setting default data
dp[0][0][0] = 1;
// Iterating on row #i
for (int i = 1; i <= n; i++)
// Row #i has state j
for (int j = 0; j < states(n); j++) {
if (!dp_ok_2d[j]) // Inlegitimate even on this position
continue;
int c_kings = get_digs(j);
// If row #i-1 has state k
for (int k = 0; k < states(n); k++) {
if (!dp_ok_2d[k])
continue;
if (!dp_ok[j][k])
continue;
int o_kings = get_digs(k);
// printf("%d %d %d | %d %d\n", i, j, k, c_kings, o_kings); // Debug only
for (int l = c_kings + o_kings; l <= K; l++)
dp[i][l][j] += dp[i - 1][l - c_kings][k];
}
}
lli res = 0;
for (int i = 0; i < states(n); i++)
res += dp[n][K][i];
printf("%lld\n", res);
return 0;
}