Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
Solution
果然啊 状压题都是一个套路
和前面那个noi的题是一个套路 具体实现也基本一样
就是记录的状态少记录一行 多记录一个k表示所放的国王数为k
然后判断的时候左移右移and一下下就OK了
具体见代码吧
(想不到自己也可以秒切省选题系列)
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int n,k,i,j,t,l,s;
ll ans;
int pd[512],get[512];
ll f[10][512][81];
int gett(int x) {
int sum=0;
int j=1;
while (x) {
if (x&j) {
sum++;
x-=j;
}
j*=2;
}
return sum;
}
bool check(int s) {
if (s&(s<<1)||s&(s>>1)) return false;
return true;
}
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
scanf("%d%d",&n,&k);
s=(1<<n)-1;
for (i=0;i<=s;i++) get[i]=gett(i);
for (i=0;i<=s;i++) {
if (check(i)) pd[i]=1;
if (pd[i]&&get[i]<=k) f[1][i][get[i]]++;
}
for (i=1;i<=n-1;i++) {
// if (i==9) printf("%d",i);
for (j=0;j<=s;j++) {
if (!pd[j]||get[j]>k) continue;
for (t=0;t<=k;t++) {
for (l=0;l<=s;l++) {
if (!pd[l]||t+get[l]>k) continue;
if (l&j||l&(j>>1)||l&(j<<1)) continue;
f[i+1][l][t+get[l]]=(ll)(f[i][j][t]+f[i+1][l][t+get[l]]);
}
}
}
}
for (i=0;i<=s;i++)
ans+=f[n][i][k];
printf("%lld",ans);
}