[SCOI2005]互不侵犯

Description

BZOJ1087

Solution

古老的状压DP

\(f[i][j][S]\)表示第i行的状态是S,选了j个国王的方案数,转移方程不难yy出来,滚动一下数组就好了。

emmm...其实这个题可以打表。

Code

#include <cstdio>

const int M = 100;
const int N = 10;
const int B = (1 << 10) + 10;
typedef long long LL;

int tot, n, K;
LL f[2][M][B], s[M], sz[M];

void dfs(int pos, int S, int SZ) {
	if (pos >= n) {
		if (!(S&(1<<n))) s[++tot] = S, sz[tot] = SZ;
		return;
	}
	if ( pos == 0 || !(S & ( 1 << (pos-1) ) ) ) dfs(pos + 2, S|(1<<pos), SZ+1);
	dfs(pos+1, S, SZ);
}

LL dp() {
	dfs(0, 0, 0);
	f[1][0][0] = 1;
	int p = 0;
	for (int i = 1; i <= n; ++i, p ^= 1) {
		for (int kk = 0; kk <= K; ++kk) {
			for (int j = 1; j <= tot; ++j) if (kk + sz[j] <= K) {
				LL &S = s[j];
				f[p][kk + sz[j]][S] = 0;
				for (int k = 1; k <= tot; ++k) {
					LL &T = s[k];
					if (!(S&T) && !(S&(T<<1)) && !(S&(T>>1))) f[p][kk+sz[j]][S] += f[p^1][kk][T];
				}
			}
		}
		
	}
	LL ans = 0;
	for (int i = 1; i <= tot; ++i) ans += f[p^1][K][s[i]];
	return ans;
}

int main () {
	scanf("%d%d", &n, &K);
	printf("%lld\n", dp());
}
posted @ 2018-07-30 21:11  wyxwyx  阅读(135)  评论(0编辑  收藏  举报