dp--状压dp
Problem Description
互不侵犯
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
Analysis of ideas
把每一行的每一个状态用一个二进制数表示
定义dp[i][j][k]为第i行,状态为j,已经放了k个棋子的方案数
Accepted code
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
int dp[10][1024][100]; //第i行状态为j,放了k个国王
vector<int> v; //枚举可用的状态
int count(int x) //计算x1的个数
{
int res = 0;
while(x)
{
res += x%2;
x /= 2;
}
return res;
}
signed main()
{
cin>>n>>k;
int mx = 1<<n; //状态最多有1<<n个
for(int i = 0; i < mx; i++)
{
if((i&(i<<1)) == 0 && (i&(i>>1)) == 0) v.push_back(i); //左边和右边没有1就是可用的状态
}
dp[0][0][0] = 1; //初始化
for(int i = 1; i <= n; i++)
{
for(int j : v) //枚举第i行状态j
{
for(int l : v) //枚举第i-1行l
{
if((j&l) || (j&(l<<1)) || (j&(l>>1))) continue; //不能互相攻击到
for(int h = 0; h <= k; h++) //枚举已经放置的国王个数
{
dp[i][j][h+count(j)] += dp[i-1][l][h];
}
}
}
}
int ans = 0;
for(int i : v)
{
ans += dp[n][i][k];
}
cout<<ans<<endl;
return 0;
}