BZOJ 1087 SCOI2005 互不侵犯King 狀壓DP
阿新 • • 發佈:2017-08-08
ble blog ace ans con 1的個數 spa algo get
題目大意:給定n*n的國際象棋棋盤。在上面放k個國王,要求國王之間互不攻擊。求方案數
n<=⑨
狀壓DP。將每一行的方案二進制壓成一維,令f[i][j][k]為第i行用去j個國王狀態為k的方案數。然後狀態轉移例如以下:
f[i][j][k]=Σf[i-1][j-digit[k]][l]
當中l&k=0,l>>1&k=0,l<<1&k=0,digit[k]為k的二進制中1的個數
暴力轉移就可以
記得開long long
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; int n,m; bool map[512][512],usable[512]; ll f[10][100][512],ans; int digit[512]; bool Judge(int x,int y) { if(x&y) return false; if(x<<1&y) return false; if(x>>1&y) return false; return true; } bool Usable(int x) { if(x<<1&x) return false; if(x>>1&x) return false; return true; } int Get_Digit(int x) { int re=0; while(x) re+=x&1,x>>=1; return re; } int main() { int i,j,k,l; cin>>n>>m; for(i=0;i<1<<n;i++) for(j=0;j<1<<n;j++) if( Judge(i,j) ) map[i][j]=1; for(i=0;i<1<<n;i++) digit[i]=Get_Digit(i); for(i=0;i<1<<n;i++) usable[i]=Usable(i); f[0][0][0]=1; for(i=1;i<=n;i++) for(j=0;j<=m;j++) for(k=0;k<1<<n;k++) if(usable[k]&&digit[k]<=j) for(l=0;l<1<<n;l++) if(usable[l]&&map[k][l]&&digit[k]+digit[l]<=j) f[i][j][k]+=f[i-1][j-digit[k]][l]; for(i=0;i<1<<n;i++) ans+=f[n][m][i]; cout<<ans<<endl; }
BZOJ 1087 SCOI2005 互不侵犯King 狀壓DP