首页 > 代码库 > BZOJ 1087 SCOI 2005 互不侵犯King 状压DP

BZOJ 1087 SCOI 2005 互不侵犯King 状压DP

题目大意:一个国王可以攻击到旁边8个位置的格子,现在给出一个N*N的方格,向其中放k个国王,问有多少中摆放方法。


思路:状压DP,f[i][j][k],其中i是行数,j是状态,k是已经取了多少国王。然后暴力枚举状态,看相邻两行之间有没有冲突,若没有冲突,那么就转移。

注意要开long long 


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int cnt,k;
long long f[15][1000][100];

inline int Set(int status)
{
	int re = 0;
	while(status)
		re += status&1,status >>= 1;
	return re;
}

inline bool Judge(int x,int y)
{
	static bool v[11];
	memset(v,false,sizeof(v));
	int p = 1;
	while(x) {
		if(x&1) {
			if(v[p - 1]|v[p]|v[p + 1])	return false;
			 v[p] = true;
		}
		x >>= 1;
		++p;
	}
	p = 1;
	while(y) {
		if(y&1) {	
			if(v[p - 1]|v[p]|v[p + 1])	return false;
			v[p] = true;
		}
		y >>= 1;
		++p;
	}
	return true;
}

int main()
{ 
	cin >> cnt >> k;
	for(int status = 0; status < (1 << cnt); ++status)
		if(Judge(status,0))
			f[1][status][Set(status)] = 1;
	for(int i = 2; i <= cnt; ++i)
		for(int s = 0; s < (1 << cnt); ++s)
			for(int _s = 0; _s < (1 << cnt); ++_s)
				if(Judge(s,_s)) {
					int temp = Set(_s);
					for(int z = 0; z <= k - temp; ++z)
						f[i][_s][z + temp] += f[i - 1][s][z];
				}
	long long ans = 0;
	for(int status = 0; status < (1 << cnt); ++status)
		ans += f[cnt][status][k];
	cout << ans << endl;
	return 0;
}


BZOJ 1087 SCOI 2005 互不侵犯King 状压DP