BZOJ1087 [SCOI2005] 互不侵犯King (状压DP)

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

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

Output
  方案数。
  
Sample Input
3 2

Sample Output
16

解法:

定义 d p [ i ] [ j ] [ s ] dp[i][j][s] dp[i][j][s] 为当前考虑到第 i i i 行,已经放置了 j j j 个国王 且 第 i i i 行的状态为 s s s 的方案数
可以预先处理出当前行的合理方案,以及对应的棋子数

Code:

typedef long long ll;
const int MX = 1 << 9;

int cnt[MX];
ll dp[10][100][MX];
int num;
int sta[100];


bool check(int i,int j){
	if(sta[i] & sta[j] || (sta[i] & (sta[j] << 1)) || (sta[i] & (sta[j] >> 1))) return false;
	return true;
}
int main(){
	int n,k;scanf("%d %d",&n,&k);
	for(int i = 0;i < (1 << n);++i){
		cnt[i] = cnt[i >> 1] + (i & 1);
	}
	for(int i = 0;i < (1 << n);++i){
		if((i & (i << 1)) || (i & (i >> 1))) continue;
		sta[num++] = i;
		dp[1][cnt[i]][i] = 1;
	}
	for(int r = 2;r <= n;++r){
		for(int i = 0;i < num;++i){//这一行的状态
			for(int j = 0;j < num;++j){//上一行的状态
				if(check(i,j)){
					for(int t = cnt[sta[j]];t <= k;++t){
						dp[r][t + cnt[sta[i]]][sta[i]] += dp[r-1][t][sta[j]];
					}
				}
			}
		}
	}
	ll res = 0;
	for(int i = 0;i < num;++i){
		res += dp[n][k][sta[i]];
	}
	printf("%lld\n", res);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值