bzoj 1087: [SCOI2005]互不侵犯King

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 2600   Solved: 1540
[ Submit][ Status][ Discuss]

Description

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

Input

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

Output

  方案数。

Sample Input

3 2

Sample Output

16

HINT

Source

[ Submit][ Status][ Discuss]


#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 10
#define ll long long 
using namespace std;
int n,m,tot,cnt[1<<N];
bool line[1<<N],ok[1<<N][1<<N];
ll f[N][N*N][1<<N];
int main()
{
	scanf("%d%d",&n,&m);
	tot=(1<<n)-1;//每一行总共的状态数 
	for (int i=0;i<=tot;i++)
	 if (((i>>1)&i)==0)//右移一位,所有位置就全都差开了一位,如果这是有一个位置运算后的值为1,则说明有两个国王挨在一起了 
	  {
	  	for (int j=i;j>0;j>>=1)//统计当前状态中放置了多少个国王 
	  	 cnt[i]+=(j&1);
	  	line[i]=true;//当前状态合法 
	  }
	for (int i=0;i<=tot;i++)
	 if (line[i])
	  {
	  	for (int j=0;j<=tot;j++)
	  	 if (line[j])
	  	  if ((i&j)==0&&((i>>1)&j)==0&&((j>>1)&i)==0)//判断两行之间是否冲突 
	  	   ok[i][j]=true;
	  }
	for (int i=0;i<=tot;i++)
	 if (line[i])
	  f[1][cnt[i]][i]=1;//f[i][j][k]表示放置到第I行,一共放置了J个国王,当前行的状态为K 
	for (int p=2;p<=n;p++)
	 for (int i=0;i<=tot;i++)
	  if (line[i])
	   for (int j=0;j<=tot;j++)
	    if (line[j])
	     if (ok[i][j])
	      for (int k=cnt[i];k+cnt[j]<=m;++k)
	       f[p][k+cnt[j]][j]+=f[p-1][k][i];
	ll ans=0;
	for (int i=0;i<=tot;++i)
	 ans+=f[n][m][i];
	cout<<ans<<endl;
}


你可能感兴趣的:(bzoj 1087: [SCOI2005]互不侵犯King)