状态压缩DP 小国王
题目:
【题目】
在 n×n 的棋盘上放 k 个国王,国王可攻击相邻的 8 个格子,求使它们无法互相攻击的方案总数。
【输入格式】
共一行,包含两个整数 n 和 k。
1≤n≤10 ,0≤k≤n2
【输出格式】
共一行,表示方案总数,若不能够放置则输出0。
【输入样例】
3 2
【输出样例】
16
思路
由于每一个格子只有放和不放两种情况,可以用0和1表达,而此时对于0101这样表达状态可以表达成一个二进制数,即状态压缩.


#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
const int N =12;
int n,k;
vector<int >s;
vector<int >h[1<<N];//每个状态可以转移到其他状态的集合
int num[1<<N];//每个状态包含的国王数
long long f[N][N*N][1<<N];
//f(i,j,a) 表示前 i 行放了 j 个国王 ,第 i行第 a个状态的方案数
int main(){
cin>>n>>k;
for(int i=0;i<(1<<n);i++){
if(!(i&i>>1)){
//不存在连续的 1
s.push_back(i);
for(int j=0;j<n;j++){
num[i]+=(i>>j&1);//该状态包含的国王数
}
}
}
for(int i=0;i<s.size();i++){
for(int j=0;j<s.size();j++){
int a=s[i],b=s[j];
if(!(a&b) && !(a&b>>1) && !(a&b<<1)){
h[i].push_back(j);//保存可以转移的状态
}
}
}
f[0][0][0]=1;//不放国王也是一种方案
for(int i=1;i<=n+1;i++){
for(int j=0;j<=k;j++){
for(int a=0;a<s.size();a++){
for(int b=0;b<h[a].size();b++){
int c=num[s[a]];
if(j>=c){//可以继续放国王
f[i][j][a]+=f[i-1][j-c][h[a][b]];
}
}
}
}
}
cout<<f[n+1][k][0]<<endl;
return 0;
}
// freopen("testdata.in", "r", stdin);

浙公网安备 33010602011771号