目录
显示
题目链接
https://www.luogu.org/problem/P1896
题解
比较经典的状压 DP 题。
用 \(f(i,j,l)\) 表示处理到第 \(i\) 行,当前行状态为 \(j\),且已经放置 \(l\) 个国王时的方案数。
其中 \(j\) 的含义是:把 \(j\) 转换为二进制数后,对应位为 \(0\) 代表该列不放国王,否则放国王。
首先 DFS 预处理出一行的所有合法状态以及每个状态部署的国王数,接下来枚举该行的可能状态进行转移。
同行内的冲突在 DFS 预处理的时候已经排除了,接下来考虑处理每一行与上一行的冲突:
- 该行国王的上面已经有国王;
- 该行国王的左上角已经有国王;
- 该行国王的右上角已经有国王。
转移的时候这几种情况需要及时排除。
#include <iostream>
#include <algorithm>
using namespace std;
long long sta[2005],sit[2005],f[15][2005][105];
int n,k,cnt;
void dfs(int x,int num,int cur)
{
if(cur>=n)
{
sit[++cnt]=x;
sta[cnt]=num;
return;
}
dfs(x,num,cur+1);
dfs(x+(1<<cur),num+1,cur+2);
}
int main()
{
cin>>n>>k;
dfs(0,0,0);
for(int i=1;i<=cnt;i++)
f[1][i][sta[i]]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=cnt;j++)
for(int l=1;l<=cnt;l++)
{
if(sit[j]&sit[l])continue;
if((sit[j]<<1)&sit[l])continue;
if(sit[j]&(sit[l]<<1))continue;
for(int p=sta[j];p<=k;p++)
f[i][j][p]+=f[i-1][l][p-sta[j]];
}
long long ans=0;
for(int i=1;i<=cnt;i++)
ans+=f[n][i][k];
cout<<ans<<endl;
return 0;
}