[Luogu P1896][SCOI2005]互不侵犯

[Luogu P1896][SCOI2005]互不侵犯

题目描述

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

 

输入输出格式

输入格式

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

 

输出格式

所得的方案数

 

输入输出样例

输入样例#1

3 2

 

输出样例#1

16

 

思路

据说是入门状压DP题(NOIP2017D2T2写得心灰意冷的我误打误撞找到了这个),然而并没有做过

$f[i][j][s]$表示DP到第$i$行,状态为$j$,放了$s$个国王。

$f[i][j][s]=\sum_{j’\&j=0,j’\&(j<<1)=0, (j'<<1)\&j=0}f[i][j'][s-j.count()]$

 

代码

#include <iostream>
#include <cstdio>
#include <bitset>
using namespace std;

int n, k;
bool ok[1<<10];
long long f[11][1<<10][90], ans;

int main(){
	scanf("%d%d", &n, &k);
	f[0][0][0]=1;
	for(int i=0; i<(1<<n); i++)
		if((i&(i<<1))==0 && (i&(i>>1))==0)
			ok[i]=true;
	for(int i=1; i<=n; i++){
		for(int j=0; j<(1<<n); j++){
			if(!ok[j])	continue;
			bitset<10>qwq(j);
			int num=qwq.count();
			for(int s=num; s<=k; s++){
				for(int w=0; w<(1<<n); w++){
					if(!ok[w] || (w&j)!=0 || !ok[w|j] )	continue;
					f[i][j][s]+=f[i-1][w][s-num];
				}
			}
		}
	}
	for(int i=0; i<(1<<n); i++)
		ans+=f[n][i][k];
	cout<<ans<<endl;
	return 0;
}

 


[Luogu P1896][SCOI2005]互不侵犯》有1个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注