title

「BZOJ1087」[SCOI2005] 互不侵犯King - 状压dp

->戳我进原题

互不侵犯King


Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 5852 Solved: 3435


Description

\(N×N\) 的棋盘里面放 \(K\) 个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共 \(8\) 个格子。

Input

只有一行,包含两个数 \(N\)\(K\) \((1 <=N <=9, 0 <= K <= N * N)\)

Output

方案数。

Sample Input

3 2

Sample Output

16

思路

\(dfs\) 初始化每一行摆放情况和 \(1\) 的个数。 \(f\) 数组第一维表示行数,第二维表示此时的摆放情况,第三维表示已经放了多少个 \(1\) ,接下来 \(dp\) 就好了,详情见代码。

代码

#include<cstdio>
#include<cctype>
#define rg register
#define int long long
using namespace std;
int n,m;
const int N = 10;
const int maxstate = 512;
int f[N][maxstate][N*N],  state[maxstate], cnt[maxstate], tot, ans;
inline void dfs(rg int plus,rg int sum,rg int node){
	if(node >= n){
		state[++tot] = plus;
		cnt[tot] = sum;
		return ;
	}
	dfs( plus, sum, node + 1);
	dfs( plus + (1 << node), sum + 1, node + 2);
}
signed main(){
	scanf("%d %d",&n,&m);
	dfs(0,0,0);
	for(rg int i = 1; i <= tot; ++i)	f[1][i][cnt[i]] = 1;
	for(rg int i = 2; i <= n; ++i)
		for(rg int j = 1; j <= tot; ++j)
			for(rg int k = 1; k <= tot; ++k){
				if(state[j] & state[k])	continue;
				if((state[j] << 1) & state[k])	continue;
				if(state[j] & (state[k] << 1))	continue;
				for(rg int l = m; l >= cnt[j]; --l)
					f[i][j][l] += f[i-1][k][l-cnt[j]];
			}
	for(rg int i = 1; i <= tot; ++i)	ans += f[n][i][m];
	printf("%lld",ans);
	return 0;
}
posted @ 2018-09-20 15:30  Horrigue_JyowYang  阅读(83)  评论(0编辑  收藏  举报