BZOJ-1087 互不侵犯King(狀壓dp)
阿新 • • 發佈:2018-11-12
題意:給一個n*n的格子,放入k個物體,要求每個物體的相鄰8個方向都不能放物體,問方案數。
題解:dp[i][j][k]表示前i行放了j個物體,且第i行狀態為k的方案數,轉移為dp[i][j][k]=∑dp[i-1][j-num[p]][p],num[p]表示單行狀態為p能放幾個物體,可以先預處理出來,另外判斷相鄰兩行是否符合也有個很簡單的技巧,具體見程式碼。
程式碼:
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespacestd; int n, k; ll dp[11][110][(1<<10)+10]; int num[(1<<10)+10]; bool flag[(1<<10)+10]; void init(){ memset(num, 0, sizeof(num)); memset(flag, false, sizeof(flag)); for(int i = 0; i<=(1<<10); i++){ if(!(i&(i<<1))){ flag[i] = true;int ans = 0; int x = i; while(x){ if(x&1){ ans++; } x>>=1; } num[i] = ans; dp[1][num[i]][i] = 1; } } } int main(){ init(); scanf("%d %d", &n, &k);for(int i = 2; i<=n; i++){ for(int j = 0; j<=k; j++){ for(int now = 0; now<=(1<<n)-1; now++){ if(flag[now] == false){ continue; } if(num[now]>j){ continue; } for(int p = 0; p<=(1<<n)-1; p++){ if(flag[p] == false){ continue; } if((now&p) || ((now<<1)&p) || ((now>>1)&p)){ continue; } dp[i][j][now]+=dp[i-1][j-num[now]][p]; } } } } ll res = 0; for(int i = 0; i<=(1<<n)-1; i++){ res+=dp[n][k][i]; } cout<<res<<endl; return 0; }