Description
在n*n(1<=n<=10)的棋盘上放k(0<=k<=n*n)个国王(可攻击相邻的8 个格子),求使它们无法互相攻击的方案总数。
Input
输入文件仅一行为两个整数n和k。
Output
输出文件仅一行为方案总数,若不能够放置则输出0。
Sample Input
3 2
Sample Output
16
Hint
4 4
79
我们发现,对于每一行来说,有上中下三行会对中间一行产生影响,事实上,我们可以预处理出中间行的可行状态(不管上下两行),而判断是否兼容则用两行合并即可。
显然较铺砖而言,多了k的限制,于是我们多开一维,预处理可行方案的同时也可以处理出在这一行的放置数量,那么我们就得到了一个简单的递推式:
f[i][state[j]][N]+=f[i-1][state[lastj]][N-num[state[j]] 【state[j]与state[lastj]兼容】
#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
#define ll long long
int n,K;
int legal,st[1<<11],cnt[1<<11];//保存合法状态
ll ans,f[11][1<<10][101];
inline void init(){
scanf("%d%d",&n,&K);
int tot=(1<<n)-1;
Inc(i,0,tot)if(!(i&(i<<1))&&!(i&(i>>1))){
st[++legal]=i;//合法状态
for(int j=0;(1<<j)<=i;++j)if(i&(1<<j))++cnt[legal];
f[1][st[legal]][cnt[legal]]=1;
}
}
inline void dp(){
Inc(i,2,n)//第i行
Inc(j,1,legal)//第i行合法状态
Inc(k,0,K)
Inc(lastj,1,legal){
if(k-cnt[j]<0)continue;
if((st[j]&st[lastj])||(st[j]&(st[lastj]<<1))||(st[j]&(st[lastj]>>1)))continue;
f[i][st[j]][k]+=f[i-1][st[lastj]][k-cnt[j]];
}
}
int main(){
init();
dp();
Inc(i,1,legal)ans+=f[n][st[i]][K];
cout<<ans<<"\n";
return 0;
}