SCOI05互不侵犯的King

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值