SGU223骑士(状压DP)

版权声明:博主是菜鸡,但转的时候还是说一声吧 https://blog.csdn.net/qq_37666409/article/details/81233982

Description

  在n*n(1<=n<=10)的棋盘上放k(0<=k<=n*n)个国王(可攻击相邻的8 个格子),求使它们无法互相攻击的方案总数。

Input

  输入文件仅一行为两个整数n和k。

Output

  输出文件仅一行为方案总数,若不能够放置则输出0。

Sample Input

3 2

Sample Output

16

Hint

【样例输入2】
  4 4

【样例输出2】
  79

一眼状压,用1表示国王(话说真的不知道这个翻译在干什么,到底是国王还是骑士啊……)

但是不能裸上,合法状态事实上并不多,预处理一下每行的合法状态,即不允许相邻的1,存在数组s[]里

方程:当i - 1行的状态为s[p],i行的状态为s[j],且s[j]和s[p]不冲突时,f[i][j][k] += f[i - 1][p][k - sum[j]]; 其中sum[]表示该状态1的个数,f[i][j][k]表示前i行中第i行为状态s[j]且共有k个1

#include <bits/stdc++.h>
#define lowbit(x) x & -x
using namespace std;
 
const int MAXS = 1050;
const int MAXN = 11;
const int INF = 0x3f3f3f3f;
 
template <typename T> inline void read(T &x) {
    int ch = getchar();
    bool fg = false;
    for (x = 0; !isdigit(ch); ch = getchar()) {
        if (ch == '-') {
            fg = true;
        }
    }
    for (; isdigit(ch); ch = getchar()) {
        x = x * 10 + ch - '0';
    }
    if (fg) {
        x = -x;
    }
}
 
typedef pair<int, int> pii;
typedef long long LL;
 
int s[MAXS], cnt, n, ALL, sum[MAXS], K;
LL f[MAXN][MAXS][MAXN * MAXN];
 
bool Legal(int i) {
	return !(i & (i << 1));
}
 
void Init() {
	ALL = (1 << n) - 1;
	for(int i = 0; i <= ALL; i++) {
		if(Legal(i)) {
			int x = i;
			s[++cnt] = i;
			while(x) x -=  lowbit(x), sum[cnt]++;
		} 
	}
}
 
bool chk(int S, int S0) {
	if((S & S0) || (S & (S0 >> 1) || (S0 << 1) & S)) return 0;
	return 1;
}
 
namespace DP {
	void init() {
		Init();
	}
	
	void dp() {
		f[0][1][0] = 1;
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= cnt; j++) {
				for(int k = 0; k <= K; k++) {
					if(sum[j] <= k) {
						for(int p = 1; p <= cnt; p++) {
							if(chk(s[j], s[p]))
								f[i][j][k] += f[i - 1][p][k - sum[j]];
						}
					} 
				}
			}
		}
	}
}
 
signed main() {
	read(n), read(K);
	DP::init();
	DP::dp();
	LL ans = 0;
	for(int i = 1; i <= cnt; i++)  {
		ans += f[n][i][K];
	}
	printf("%lld\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37666409/article/details/81233982