【题目描述】
原题来自:SGU 223
在 n×nn×n 的棋盘上放 kk 个国王,国王可攻击相邻的 88 个格子,求使它们无法互相攻击的方案总数。
【输入】
只有一行,包含两个整数 nn 和 kk。
【输出】
每组数据一行为方案总数,若不能够放置则输出 00。
【输入样例】
3 2
【输出样例】
16
【提示】
样例输入 2
4 4
样例输出 2
79
数据范围与提示:
对于全部数据,1≤n≤10,0≤k≤n21≤n≤10,0≤k≤n2 。
1592:【例 1】国王https://ybt.ssoier.cn/problem_show.php?pid=1592
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=15,M=1<<11,K=110;
int n,m;
long long f[N][K][M];//在第i行,已经摆放了j个国王,当前行状态为k的方案数
int cnt[M];
vector<int> state;//存放合法状态
vector<int> h[M];//存放当前状态上一行的合法状态
bool check(int u){
for(int i=0;i<n;i++)
if((u>>i)&1&&(u>>i+1)&1)return false;
return true;
}
int count(int u){
int cnt=0;
for(int i=0;i<n;i++)cnt+=(u>>i)&1;
return cnt;
}
int main(){
cin>>n>>m;
for(int i=0;i<(1<<n);i++)
if(check(i)){
state.push_back(i);
cnt[i]=count(i);
}
for(int i=0;i<state.size();i++)
for(int j=0;j<state.size();j++){
int a=state[i],b=state[j];
if(check(a|b)&&(a&b)==0)
h[i].push_back(j);
}
f[0][0][0]=1;
for(int i=1;i<=n+1;i++){
for(int j=0;j<=m;j++){
for(int a=0;a<state.size();a++){
for(int &b:h[a]){
int c=cnt[state[a]];
if(j>=c)
f[i][j][a]+=f[i-1][j-c][b];
}
}
}
}
long long res = 0;
for(int a = 0; a < state.size(); a++){
res += f[n][m][a]; // 累加符合条件的方案数
}
cout<<res;//或者cout<<f[n+1][m][0]
}