Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
HINT
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
状压DP~
大清早的不太清醒……先是把国王走法看成了国际象棋里面皇后的走法想到吐血……然后数组又开小了RE到飞起……不过话说如果是皇后走法的话怎么做呢?
先预处理出每一种可能的情况cas[](只考虑单行不能相邻),然后DP,用f[k][i][j]表示枚举第i行,状态是k,已经放了(包含i行)j颗棋子的种类数,然后就像前面几道那样DP就好了~
另外注意f数组和ans都要开成long long!
#include<cstdio>
#include<iostream>
using namespace std;
#define ll long long
int n,m,cas[520],num[520],tot;
ll f[520][10][101],ans;
bool che(int u)
{
return !(u&(u>>1));
}
bool che2(int u,int v)
{
return !(u&v) && !(u&(v<<1)) && !(u&(v>>1));
}
int cal(int u)
{
int totnum=0;
for(int i=0;i<=9;i++)
if(u&(1<<i)) totnum++;
return totnum;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<(1<<n);i++)
if(che(i))
{
cas[++cas[0]]=i;num[cas[0]]=cal(i);
f[cas[0]][1][num[cas[0]]]=1;
}
for(int i=2;i<=n;i++)
for(int k=1;k<=cas[0];k++)
for(int j=1;j<=cas[0];j++)
if(che2(cas[k],cas[j]))
for(int z=num[j];z+num[k]<=m;z++) f[k][i][z+num[k]]+=f[j][i-1][z];
for(int i=1;i<=cas[0];i++) ans+=f[i][n][m];
printf("%lld\n",ans);
return 0;
}