国王 状压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的主要内容,如果未能解决你的问题,请参考以下文章