題目
放棋子問題,放的是國際象棋的王,不能放的是棋子的周圍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;
}