【洛谷P1896】[SCOI2005]互不侵犯

传送门

题目描述

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

注:数据有加强(2018/4/25)

输入格式

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

输出格式

所得的方案数

输入输出样例

输入 #1
3 2
输出 #1
16

挺好一模板

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 12;
long long dp[N][1<<N][N*N];//前i行,状态为j,放了k个国王 
int n,k,cnt;
long long ans;
int s[1<<N],num[1<<N];
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=0;i<(1<<n);i++)	
	{
		if( i&(i<<1) ) continue;
		int sum=0;
		for(int end=0;end<n;end++)
			if( i&(1<<end) ) sum++;
		s[++cnt]=i;
		num[cnt]=sum;
	}
	//预处理
	dp[0][1][0]=1;
	for(int i=1;i<=n;i++)	
		for(int j=1;j<=cnt;j++)	//枚举状态,但其实这里枚举的是状态的编号 
			for(int p=0;p<=k;p++)	
			{
				if(p>=num[j])
				for(int end=1;end<=cnt;end++)
				{
					if( !(s[end]&s[j]) && !(s[end]&(s[j]<<1)) && 
					!(s[end]&(s[j]>>1)) )
					dp[i][j][p]+=dp[i-1][end][p-num[j]];
				}	
			}
	for(int i=1;i<=cnt;i++)
		ans+=dp[n][i][k];
	printf("%lld",ans);
	return 0;
}
posted @ 2021-07-22 22:27  conprour  阅读(28)  评论(0编辑  收藏  举报