国王 状压dp

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了国王 状压dp相关的知识,希望对你有一定的参考价值。

题意:在 n × n n×n n×n 的棋盘上放 k k k 个国王,国王可攻击相邻的 8 8 8 个格子,求使它们无法互相攻击的方案总数。

思路:
将每行的国王放的情况压缩成一个状态数,这个状态数的二进制表示这个状态,1表示有国王,0表示没有这个国王。
需要提前处理能够转移的状态,当有两个相邻的1时不满足在同一行的国王放置的条件,如果两行的国王或运算出现相邻的1时,那么转移也不符合条件

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 12,M = 1<<10,K=110;

int n,m;
vector<int> state;
int cnt[M];//存储1的个数
vector<int> head[M];

ll f[N][K][M];
bool check(int x)
{
	for(int i=0;i<n;i++)
	{
		if((x>>i&1)&&(x>>i+1&1))
			return false;
	}
	return true;
}
int count(int x)
{
	int res = 0;
	for(int i=0;i<n;i++) res += x>>i&1;
	return res;
}
int main()
{
	cin>>n>>m;
	for(int i=0;i< 1<<n;i++)
		if(check(i))
		{
			state.push_back(i);
			cnt[i] = count(i);
		}
	
	for(int i=0;i<state.size();i++)
	{
		for(int j=0;j<state.size();j++)
		{
			int a = state[i],b = state[j];
			if((a&b)==0 && check(a|b))
				head[i].push_back(j);
		}
	}
	
	f[0][0][0] = 1;
	for(int i=1;i<=n+1;i++)//枚举行数
		for(int j=0;j<=m;j++)//枚举国王个数
			for(int a=0;a<state.size();a++)//枚举该行状态
				for(int b : head[a])//枚举可转移到该行的状态
				{
					int c = cnt[state[a]];//状态a中1的个数
					if(j>=c)
						f[i][j][a]+=f[i-1][j-c][b];
				}
	cout<<f[n+1][m][0]<<'\\n';
	
	return 0;
 } 

以上是关于国王 状压dp的主要内容,如果未能解决你的问题,请参考以下文章

状压DP之互不侵犯

dp--状压dp

1896 [SCOI2005]互不侵犯 状压dp

[luoguP1896] [SCOI2005]互不侵犯King(状压DP)

bzoj 1087 状压dp

BZOJ 1087 SCOI2005 互不侵犯King 状压DP