1. 程式人生 > >LOJ #10170. 「一本通 5.4 例 1」騎士

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

題目描述

在 n×nn \times nn×n 的棋盤上放 kkk 個國王,國王可攻擊相鄰的 888 個格子,求使它們無法互相攻擊的方案總數。

輸入格式

只有一行,包含兩個整數 nnn 和 kkk。

輸出格式

每組資料一行為方案總數,若不能夠放置則輸出 000。

樣例

樣例輸入 1

3 2

樣例輸出 1

16

樣例輸入 2

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;
}