在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
我们用 f[i][j][k] 代表,第 前 i 行, j 个国王,当前状态是 k ,一共有多少种方法。
我们先预处理出来哪些状态可以用。
从一个状态又可以到达哪些状态。
#include <bits/stdc++.h>
#define mem(x,v) memset(x,v,sizeof(x))
#define go(i,a,b) for (int i = a; i <= b; i++)
#define og(i,a,b) for (int i = a; i >= b; i--)
#define MID(a,b) (a + b) / 2
#define lson now << 1
#define rson now << 1 | 1
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 10;
LL f[N][N*N][1<<N];
int cnt[1<<N];
bool vis[1<<N],mp[1<<N][1<<N];
int n,m,all;
void Pre(){
int s;
go(i,0,all)
if ((i&(i>>1))==0){ //右移一位,判断两个国王是否相邻。
s = 0;
for (int x = i; x; x>>=1) s += (x&1); //这个状态有多少个国王。
cnt[i] = s; vis[i] = 1; //标记这个状态可行,
}
go(i,0,all) if (vis[i])
go(j,0,all) if (vis[j])
if ((i&j) == 0 && (i & (j>>1))==0 && (j & (i>>1))==0) mp[i][j]= 1; //判断两个状态是否可以到达。
}
int main(){
scanf("%d%d",&n,&m);
all = (1<<n) - 1;
Pre();
go(i,0,all) f[1][cnt[i]][i] = 1; //第一行的状态搞出来。
go(j,1,n-1) //第几行
go(k,0,all) if (vis[k]) //当前状态,
go(i,0,all) if (vis[i]) //转移的状态。
if (mp[k][i])
for (int p = cnt[k]; p +cnt[i] <= m; p++) //枚举有多少国王,
f[j+1][cnt[i]+p][i] += f[j][p][k]; //累加。状态转移。
LL ans = 0;
go(i,0,all) ans += f[n][m][i];
cout<<ans<<endl;
return 0;
}