国王

https://loj.ac/problem/10170

题目描述

  在\(n\times n\)的棋盘上放\(k\)个国王,国王可攻击相邻的\(8\)个格子,求使它们无法互相攻击的方案总数。

思路

  这道题的\(n\)比较小,我们考虑直接把棋盘的一行压成一个数,那么如果这个位置放了棋子,这个数的二进制下的数为\(1\),否则为\(0\),我们可以先预处理处所有满足条件的行的数,在\(dp\)列,用\(f[i][S][k]\)表示第\(i\)行状态为\(S\),到目前位置共放\(k\)个棋子的方案数,那么\(S\)可以从不互相攻击的状态转移过来,直接\(dp\)即可。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int s[600],p[600];
ll f[11][500][110];
int main()
{
	int n,k,cnt=0;
	scanf("%d%d",&n,&k);
	for(int i=0;i<(1<<n);i++)
	{
		if(i&(i<<1))continue ;
		int sum=0;
		for(int j=0;j<n;j++)
			if(i&(1<<j))sum++;
		p[++cnt]=i;
		s[cnt]=sum;
	}
	f[0][1][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=cnt;j++)
			for(int l=s[j];l<=k;l++)
			{
				for(int r=1;r<=cnt;r++)
					if(!(p[j]&p[r])&&!(p[j]&(p[r]<<1))&&!(p[j]&(p[r]>>1)))
						f[i][j][l]+=f[i-1][r][l-s[j]];
			}
	long long ans=0;
	for(int i=1;i<=cnt;i++)
		ans+=f[n][i][k];
	printf("%lld\n",ans);
}
posted @ 2019-11-12 19:13  fbz  阅读(117)  评论(0编辑  收藏  举报