状压 DP 是动态规划的一种,通过将状态压缩为整数来达到优化转移的目的。

如下图所示,可以用0/1表示状态,然后转换为十进制数进行存储,大大减少存储空间。

在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
所得的方案数
3 2
16
f[i][st][j]的定义,以及状态转移方程:
行内不能相邻,行间要检验三位。


int n, k;
ll f[9][1 << 9][82], ans;
int c(int st){
//返回st的二进制中1的个数
int cnt = 0;
while(st){
if(st%2)
cnt++;
st /= 2;
}
return cnt;
}
bool check1(int st){
//同行检验
for (int i = 0; i < n - 1;i++)
if ((st & (1 << i)) && (st & (1 << (i + 1))))
return false;
return true;
}
bool check2(int st,int st2){
//与上一行的检验
for (int i = 0; i < n;i++){
if (st & (1 << i)){
if (st2 & (1 << i))
return false;
else if (i + 1 < n && (st2 & (1 << (i + 1))))
return false;
else if (i - 1 < n && (st2 & (1 << (i - 1))))
return false;
}
}
return true;
}
void solve(){
cin >> n >> k;
for (int i = 0; i < n;i++){
for (int st = 0; st < (1 << n);st++){
if(!check1(st))
continue;
if (i == 0)
f[i][st][c(st)] = 1;
else{
for (int j = c(st); j <= k;j++){
for (int st2 = 0; st2 < (1 << n);st2++){
if(!check1(st2)||!check2(st,st2))
continue;
f[i][st][j] += f[i - 1][st2][j - c(st)];
}
}
}
}
}
for (int st = 0; st < (1 << n);st++)
ans += f[n - 1][st][k];
cout << ans << nl;
}