SGU 223 国王 状压DP
在 n×n 的棋盘上放 kk 个国王,国王可攻击相邻的 88 个格子,求使它们无法互相攻击的方案总数。
状压DP是一种比较暴力的DP。
首先dp[i][j][k]表示前i行放置k个国王,且当前行状态是j的方案数。
转移方程 dp[i][j][k] = dp[i - 1][m][k - sum[k]]
sum[k]表示第k个合法状态的放置的国王个数。
什么叫第k个合法状态。由于每行的放置规则是有限的,所以可以预处理出合法状态记录到sum里和一个st数组表示第i个合法状态的国王个数。
最后只要求 1 <= i <= cnt 下dp[n][i][k] cnt是合法状态数
ll dp[12][1 << 10 + 5][105]; int st[1 << 10 + 5]; int sum[1 << 10 + 5]; bool check(int x, int y) { if ((x & y) || (x & (y << 1)) || (x & (y >> 1))) return false; return true; } int main() { int n = readint(); int k = readint(); int cnt = 0; for (int i = 0; i < 1 << n; i++) { if (!(i & (i << 1))) { st[++cnt] = i; sum[cnt] = bitcount(i); } } for (int i = 1; i <= cnt; i++) dp[1][i][sum[i]] = 1; for (int i = 2; i <= n; i++) for (int j = 1; j <= cnt; j++) for (int m = sum[j]; m <= k; m++) for (int jj = 1; jj <= cnt; jj++) if (check(st[j], st[jj])) dp[i][j][m] += dp[i - 1][jj][m - sum[j]]; ll sum = 0; for (int i = 1; i <= cnt; i++) sum += dp[n][i][k]; Put(sum); }