LOJ #10170. 「一本通 5.4 例 1」骑士

题目描述

原题来自:SGU 223

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

输入格式

只有一行,包含两个整数 nnn 和 kkk。

输出格式

每组数据一行为方案总数,若不能够放置则输出 000。

样例

样例输入 1

3 2

样例输出 1

16

样例输入 2

扫描二维码关注公众号,回复: 3254821 查看本文章
4 4

样例输出 2

79

数据范围与提示

对于全部数据,1≤n≤10,0≤k≤n21\le n\le 10, 0\le k\le n^21≤n≤10,0≤k≤n​2​​。

这是一道最基础的状压dp

不过数组一定要开大

每层状态最高才143种

#include<cstdio>
#define ll long long
using namespace std;
inline int read()
{
	int ret=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
		ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
	return ret;
}

int n,m,cnt;
const int N=11,S=1100;
int a[S],sum[S];
ll f[N][S][105];

int main()
{
	n=read(),m=read();
	for(int i=0;i<(1<<n);i++)
	{
		if(i&(i<<1)||i&(i>>1))continue;
		a[++cnt]=i; 
		int x=i;
		while(x)
			sum[cnt]+=x&1,x>>=1;
	}
	
	for(int i=1;i<=cnt;i++)
		f[1][i][sum[i]]=1;
	for(int i=2;i<=n;i++)
		for(int j=1;j<=cnt;j++)
			for(int k=1;k<=cnt;k++)
			{
				if(a[j]&a[k]||(a[j]>>1)&a[k]||(a[j]<<1)&a[k]) continue;
				for(int l=sum[j]+sum[k];l<=m;l++)
					f[i][j][l]+=f[i-1][k][l-sum[j]];
			}
			
	ll ans=0;
	for(int i=1;i<=cnt;i++)
		ans+=f[n][i][m];
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/YYHS_WSF/article/details/82659851