洛谷 P1896 [SCOI2005]互不侵犯

題目描述

\(N×N\)的棋盤裏面放\(K\)個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各一個格子,共\(8\)個格子。spa

注:數據有增強\((2018/4/25)\)code

輸入輸出格式

輸入格式:io

只有一行,包含兩個數\(N,K ( 1 <=N <=9, 0 <= K <= N * N)\)class

輸出格式:數據

所得的方案數註釋

輸入輸出樣例

輸入樣例#1:di

3 2

輸出樣例#1:while

16

思路:見代碼註釋。co

代碼:math

/*f[i][j][k]表示第i行,狀態爲j,前面擺了k個國王時方案數*/
#include<cstdio>
#define ll long long
ll n,k,king[513],f[10][513][82],num,state[513],ans;
//state是當前狀態,king是當前狀態的國王數
int main() {
  scanf("%d%d",&n,&k);
  int maxn=1<<n;
  for(int i=0;i<maxn;++i) { //預處理出全部可能組成的狀態
    if(!(i&(i<<1))) {
      state[++num]=i;
      int res=i;
      while(res) {
        if(res&1) ++king[num];   //記錄這個狀態下國王的個數
        res>>=1;
      }
    }
  }
  for(int i=1;i<=num;++i) 
    if(king[i]<=k) f[1][i][king[i]]=1;
  //全部狀態下的國王個數不能超過k
  for(int i=2;i<=n;++i) {   //狀態轉移,注意判斷合法,衝突便可。
    for(int j=1;j<=num;++j) {
      for(int l=1;l<=num;++l) {
        if(state[j]&state[l]) continue;
        if(state[j]&(state[l]<<1)) continue;
        if((state[j]<<1)&state[l]) continue;
        for(int s=1;s<=k;++s) {
          if(s+king[j]>k) continue;
          f[i][j][king[j]+s]+=f[i-1][l][s];
        }
      }
    }
  } 
  for(int i=1;i<=n;++i)
    for(int j=1;j<=num;++j) 
      ans+=f[i][j][k];
  printf("%lld\n",ans);
  return 0;
}
相關文章
相關標籤/搜索