题目描述
在n*n(1<=n<=10)的棋盘上放k(0<=k<=n*n)个国王(可攻击相邻的8 个格子),求使它们无法互相攻击的方案总数。
输入格式
输入文件仅一行为两个整数n和k。
输出格式
输出文件仅一行为方案总数,若不能够放置则输出0。
样例数据
样例输入
样例数据#1
3 2
样例数据#2
4 4
样例输出
样例数据#1
16
样例数据#2
79
题目分析
状压裸题,先做poj2411
不过有国王个数限制,要把国王个数写入状态。
源代码
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
long long cnt=0,ans=0,f[15][1105][205];
int n,King,State[1105],king[1105];
bool Check(int a,int b) { //检查状态State[a]与State[b]是否冲突
return !(State[a]&State[b])&&!(State[a]&(State[b])<<1)&&!(State[a]&(State[b])>>1); //上一排的左右3格都不能有国王
}
int main() {
scanf("%d%d",&n,&King);
for(int i=0; i<(1<<n); i++) { //枚举每行状态初始化
if(i&(i<<1))continue; //左右冲突
cnt++;
State[cnt]=i; //保存状态
for(int j=0; j<n; j++)
if(i&(1<<j))king[cnt]++; //统计国王个数
}
f[0][1][0]=1; //初始条件:第0行全为0
for(int i=1; i<=n; i++) //阶段:行
for(int j=1; j<=cnt; j++) //枚举状态
for(int k=0; k<=King; k++) //枚举国王数
if(k>=king[j])
for(int t=1; t<=cnt; t++) //枚举i-1行状态
if(Check(j,t))f[i][j][k]+=f[i-1][t][k-king[j]];
for(int i=1; i<=cnt; i++)ans+=f[n][i][King];
printf("%lld\n",ans);
return 0;
}