HYSBZ - 1087

题目
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。

Input
  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output
  方案数。

Sample Input
3 2
Sample Output
16
解题思路
由于(1<=N<=9),可以用0~2^n-1个数来表示每一行的状态。
对于第i行的每个格子是否能放国王,取决于第i-1行的状态。
所以可以先预处理第i行与第i-1行的合法状态。

f[i][j][k]表示前i行放了k个国王使得第i行的状态为j的方案数。
j为第i-1行状态,num为第i行的状态r贡献了多少个国王,
若状态r与j合法且k+num<=m则
f[i][r][k+num]=∑(f[i-1][j][k])

代码

#include <cstdio>
#include <iostream>
using namespace std;
long long f[15][777][100];
int n,m;
bool sym[1010];
bool check(int x)
{
    for (int i=1;i<n;i++)
	  {
	  	int aa=x&1;
	  	x>>=1;
	  	int bb=x&1;
	  	if (aa==1 && bb==1) return false;
	  }
	return true;  
}
bool ck(int a,int b)
{
	int aa[15],bb[15];
	aa[0]=0;aa[n+1]=0;
	bb[0]=0;bb[n+1]=0;
	for (int i=1;i<=n;i++)
	{
		aa[i]=a&1;
		bb[i]=b&1;
		a>>=1;
		b>>=1;
	}
	for (int i=1;i<=n;i++)
	  if (aa[i]==1 && (bb[i-1]==1 || bb[i+1]==1 || bb[i]==1))return false;
	  
	return true;
}
int work(int x)
{
	int ans=0;
	while (x!=0)
	{
		if (x&1==1) ans++;
		x>>=1;
	}
	return ans;
}
int main()
{

	scanf("%d%d",&n,&m);
	f[0][0][0]=1;
	for (int i=0;i<(1<<n);i++)
	  if (check(i)) sym[i]=true;
	for (int i=1;i<=n;i++)
	  for (int j=0;j<(1<<n);j++)
	    if (sym[j])
	    {
	    for (int r=0;r<(1<<n);r++)
	      if (sym[r])
	      {
	      for (int k=0;k<=m;k++)
	        if (f[i-1][j][k]!=0)
	        {
	      	   if (ck(j,r))
	      	   	{
	      	   	  int num=work(r);
	      	   	  if (k+num>m) continue;
	      	   	  f[i][r][k+num]+=f[i-1][j][k];
	      	   	}
	      	   
	      	}
	      }
	    }
	long long ans=0;   	
	for (int j=0;j<(1<<n);j++)
	    ans+=f[n][j][m];
	cout<<ans<<endl;			        	
}
发布了42 篇原创文章 · 获赞 0 · 访问量 604

猜你喜欢

转载自blog.csdn.net/weixin_45723759/article/details/103993890