版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目
放棋子问题,放的是国际象棋的王,不能放的是棋子的周围8格
题解
周围8格相对好判断的,先预处理,把所有可以一行存储的给找出来,判断方式是(i>>1)&i==0
,并记忆存储每一种方式的棋子数,根据棋子数进行排序,方便之后的剪枝。
接着就是判断上下两行之间的关系,就是将上一行的状态,上一行前移一格,后移一格之后的三种状态与这一行的状态进行与操作只要结果不为0,就不可以
代码
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
struct e
{
int v,n;
}dp[1024];
int cnt,n,k;
ll qi[105][100][1024];
bool cmp(e a,e b)
{
if(a.n==b.n) return a.v<b.v;
else return a.n<b.n;
}
int suan(int i)
{
int num=0;
while(i){
if(i&1) num++;
i=(i>>1);
}
return num;
}
void init(int n)
{
for(int i=0;i<=(1<<n)-1;i++){
if(((i>>1)&i)==0){
dp[++cnt].v=i;
dp[cnt].n=suan(i);
}
}
sort(dp+1,dp+cnt+1,cmp);
/*for(int i=1;i<=cnt;i++){
cout<<dp[i].n<<' '<<dp[i].v<<endl;
}*/
}
int judge(int m,int n)
{
if(n&m) return 0;
if((n>>1)&m) return 0;
if((n<<1)&m) return 0;
return 1;
}
void ans(int m)
{
for(int i=1;i<=cnt;i++){//遍历上一层的状态
for(int j=0;j<=k;j++){//遍历之前所有层的棋子数
for(int l=1;l<=cnt;l++){//遍历这一层的状态
if((dp[l].n+j)>k) break;
if(judge(dp[l].v,dp[i].v)) qi[m][j+dp[l].n][dp[l].v]+=qi[m-1][j][dp[i].v];
}
}
}
}
int main()
{
cin>>n>>k;
init(n);
for(int i=1;i<=cnt;i++){
qi[1][dp[i].n][dp[i].v]=1;
}
for(int i=2;i<=n;i++){
ans(i);
}
ll num=0;
for(int i=1;i<=cnt;i++){
num+=qi[n][k][dp[i].v];
}
cout<<num<<endl;
}