题目描述
原题来自: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≤n2。
这是一道最基础的状压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;
}