傳送門php
給你一個\(n*n\)的格子,若是第\(i\)個格子放入了棋子,則八聯通方向都不能放置棋子,問放置\(k\)個棋子的方案數。c++
很明顯能夠進行\(dp\),又由於\(n\)很是的小,所以咱們能夠採用狀態壓縮的方法。設\(dp[i][state][k]\)爲當前第\(i\)行的狀態爲\(state\)時,放置了\(k\)個棋子的方案數。spa
當前第i行的狀態,顯然能夠由第\(i-1\)行的狀態轉移而來,而由於要知足八聯通不能有棋子,所以在咱們的狀壓\(state[I]\),和\(state[j]\)中,只要知足\(state[i]\&(state[i]<<1)\)、\(state[j]\&(state[j]<<1)\)、\(state[i]\&(state[j]<<1)\)、\(state[i]\&(state[j]>>1)\)、\(state[I]\&state[j]\)均大於\(0\)便可。最後有狀態轉移方程:\(dp[i][state[i]][bit(state[i])+k]+=dp[I-1][bit(state[j])][k]\)code
總的時間複雜度爲:\(\mathcal{O}(2^{2*n}*k)\)get
#include <bits/stdc++.h> #define maxn 10 using namespace std; long long dp[maxn][1<<maxn][maxn*maxn]; int getbit(int x){ int res=0; while(x){ if(x&1) res++; x>>=1; } return res; } int main() { int n,k; memset(dp,0,sizeof(dp)); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ int all=1<<n; for(int j=0;j<all;j++){ if(j&(j<<1)) continue; if(i==1){ if(getbit(j)<=k) dp[i][j][getbit(j)]++; continue; } for(int kk=0;kk<all;kk++){ if(kk&(kk<<1)) continue; if((j&kk)||(j&(kk<<1))||(j&(kk>>1))) continue; for(int ll=0;ll<=k;ll++){ dp[i][j][getbit(j)+ll]+=dp[i-1][kk][ll]; } } } } long long res=0; int all=1<<n; for(int i=0;i<all;i++){ res+=dp[n][i][k]; } printf("%lld\n",res); return 0; }