洛谷P1896题解
分析
首先,题目意思总结,放的位置不相邻并且左移右移后与下一层 \(and\)!\(=1\)
第一步预处理出所有在同一行中不相邻的方案数记为meiju[]
其次定义 \(dp\) 数组,\(f[i][j][k]\) 即在第 \(i\) 行,状态为 \(j\) ,国王数为 \(k\) 的方案数
\(sum_ep(j)\) 在进行预处理 \(meiju\) 时同时预处理出每种可行方案的国王 \(k\) 值用 \(num\) 数组来储存每种状态的国王数
\(pd\)(\(int\) \(x\) ,\(int\) \(k\))判断左移右移后是否合法
三重循环,一层行数,二层状态,三层状态,判断两层状态是否合法,若合法进行下一步循环,循环国王数m
状态转移方程:\(f[i][j][num[j]+z]\)+=\(f[i-1][k][z]\)
最后 \(ans\) += \(f[n][i][m]\)(加上所有状态下的值,如果状态不合法就是 \(0\) 。可以不用考虑)
code
/*
work by Simon
*/
#include<bits/stdc++.h>
#define maxn 10
#define MAXN 1<<10
using namespace std;
int n,m,cnt;
long long ans;
int meiju[MAXN],num[MAXN];
long long f[maxn][MAXN][maxn*maxn];//不开long long 见祖宗!!!
bool pd(int x,int y)
{
if(!(x&y)&&(!(x&(y<<1)))&&(!(x&(y>>1))))
return true;
return false;
}
int sum_ep(int i)
{
int res=0;
while(i)
{
if(i&1)res++;
i>>=1;
}
num[cnt]=res;
return res;
}
int main()
{
std::ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
int MAX=(1<<n);
for(int i=0;i<MAX;i++)
if(!(i&(i<<1))&&(!(i&(i>>1))))meiju[++cnt]=i,f[1][cnt][sum_ep(i)]=1;//
for(int i=2;i<=n;i++)//预处理meiju数组时已经将第1行的所有情况统计下来了 ,此时从2开始
for(int j=1;j<=cnt;j++)
{
int x=meiju[j];
for(int k=1;k<=cnt;k++)
{
int y=meiju[k];
if(pd(x,y))
for(int z=0;z<=m;z++)f[i][j][num[j]+z]+=f[i-1][k][z];
}
}
for(int i=1;i<=cnt;i++)ans+=f[n][i][m];
cout<<ans;
return 0;
}

浙公网安备 33010602011771号