其他分享
首页 > 其他分享> > 状压dp

状压dp

作者:互联网

题目链接:

https://www.luogu.com.cn/problem/P1896

题意:

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

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 15, M = 150, K = 1500;
LL n, k;
LL cnt[K];	//每个状态的二进制中 1 的数量
LL tot;	//合法状态的数量
LL st[K];	//合法的状态
LL dp[N][M][K];	//第 i 行,放置了 j 个国王,状态为 k 的方案数
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin >> n >> k;
	for (int s = 0; s < (1 << n); s ++ ){  //找出合法状态
		LL sum = 0, t = s;
		while(t){  //计算 1 的数量
			sum += (t & 1);
			t >>= 1;
		}
		cnt[s] = sum;
		if ( (( (s << 1) | (s >> 1) ) & s) == 0 ){  //判断合法性
			st[ ++ tot] = s;
		}
	}
	dp[0][0][0] = 1;
	for (int i = 1; i <= n + 1; i ++ ){
		for (int j1 = 1; j1 <= tot; j1 ++ ){	//当前的状态
			LL s1 = st[j1];
			for (int j2 = 1; j2 <= tot; j2 ++ ){	//上一行的状态
				LL s2 = st[j2];
				if ( ( (s2 | (s2 << 1) | (s2 >> 1)) & s1 ) == 0 ){
					for (int j = 0; j <= k; j ++ ){
						if (j - cnt[s1] >= 0)
							dp[i][j][s1] += dp[i - 1][j - cnt[s1]][s2];
					}
				}
			}
		}
	}
	cout << dp[n + 1][k][0] << "\n";
	return 0;
}

标签:cnt,int,LL,状压,tot,s1,dp
来源: https://www.cnblogs.com/Hamine/p/16487713.html