BZOJ 1087 SCOI2005 互不侵犯King 状压DP
题目大意:给定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; }
posted on 2017-08-08 20:49 gavanwanggw 阅读(116) 评论(0) 编辑 收藏 举报