题目
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
解题思路
由于(1<=N<=9),可以用0~2^n-1个数来表示每一行的状态。
对于第i行的每个格子是否能放国王,取决于第i-1行的状态。
所以可以先预处理第i行与第i-1行的合法状态。
f[i][j][k]表示前i行放了k个国王使得第i行的状态为j的方案数。
j为第i-1行状态,num为第i行的状态r贡献了多少个国王,
若状态r与j合法且k+num<=m则
f[i][r][k+num]=∑(f[i-1][j][k])
代码
#include <cstdio>
#include <iostream>
using namespace std;
long long f[15][777][100];
int n,m;
bool sym[1010];
bool check(int x)
{
for (int i=1;i<n;i++)
{
int aa=x&1;
x>>=1;
int bb=x&1;
if (aa==1 && bb==1) return false;
}
return true;
}
bool ck(int a,int b)
{
int aa[15],bb[15];
aa[0]=0;aa[n+1]=0;
bb[0]=0;bb[n+1]=0;
for (int i=1;i<=n;i++)
{
aa[i]=a&1;
bb[i]=b&1;
a>>=1;
b>>=1;
}
for (int i=1;i<=n;i++)
if (aa[i]==1 && (bb[i-1]==1 || bb[i+1]==1 || bb[i]==1))return false;
return true;
}
int work(int x)
{
int ans=0;
while (x!=0)
{
if (x&1==1) ans++;
x>>=1;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
f[0][0][0]=1;
for (int i=0;i<(1<<n);i++)
if (check(i)) sym[i]=true;
for (int i=1;i<=n;i++)
for (int j=0;j<(1<<n);j++)
if (sym[j])
{
for (int r=0;r<(1<<n);r++)
if (sym[r])
{
for (int k=0;k<=m;k++)
if (f[i-1][j][k]!=0)
{
if (ck(j,r))
{
int num=work(r);
if (k+num>m) continue;
f[i][r][k+num]+=f[i-1][j][k];
}
}
}
}
long long ans=0;
for (int j=0;j<(1<<n);j++)
ans+=f[n][j][m];
cout<<ans<<endl;
}