在N×N的棋盤裏面放K個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各一個格子,共8個格子。ios
注:數據有增強(2018/4/25)git
輸入格式:函數
只有一行,包含兩個數N,K ( 1 <=N <=9, 0 <= K <= N * N)spa
輸出格式:code
所得的方案數get
輸入樣例#1:it
3 2
輸出樣例#1:io
16
由\(n \le 9\)能夠看粗應該是個狀壓DPclass
因此就能夠高高興興個設狀態了stream
用\(f[i][j][k]\)表示前\(i\) 行 最後一行狀態爲\(j\)放\(k\)個的方案數
須要兩個函數判斷狀態合不合法還有放置的個數
inline int bitcnt(int x,int ans=0){ for(;x;x&=(x-1),++ans); return ans; }
用來判斷二進制中有幾個一(\(x\&=x-1\)是否是很熟悉沒錯就是今年初賽題)
inline bool pd(int x){ return (((x<<1)&x)||((x>>1)&x)); }
這個用來判斷一個數合不合法(一個1左右不能有另外一個1)
而後就能夠列狀態轉移方程了
\(\displaystyle f[i][j][k]=\sum_{l與j合法}f[i-1][l][k-bitcnt(k)]\)
#include<iostream> #include<cstdio> using namespace std; #define int long long int mian(){ int s=0,f=1;char ch; while(!isdigit(ch=getchar()))(ch=='-')&&(f=-1); for(s=ch-'0';isdigit(ch=getchar());s=s*10+ch-'0'); return s*f; } /* 子供の時の夢は言えますか その夢すら 溝に 舍てたのは */ int f[10][(1<<10)+1][100]; int n,m; inline int bitcnt(int x,int ans=0){ for(;x;x&=(x-1),++ans); return ans; } inline bool pd(int x){ return (((x<<1)&x)||((x>>1)&x)); } signed main(){ n=mian(),m=mian(); const int U = (1<<n)-1; f[0][0][0]=1; for(int i=1;i<=n;++i){ for(int k=0;k<=U;++k){ if(pd(k))continue; for(int l=0;l<=U;++l){ if(pd(l))continue; if(l&k)continue; if((l>>1)&k)continue; if((l<<1)&k)continue; // cout<<k<<' '<<l<<endl; int c=bitcnt(k); for(int o=c;o<=m;++o) f[i][k][o]+=f[i-1][l][o-c]; } } } int ans=0; for(int i=0;i<=U;++i)ans+=f[n][i][m]; cout<<ans<<endl; return 0; }