【传送门:BZOJ1087】
简要题意:
输入一个n和k,表示现在有一个n*n的棋盘,每一个格子可以放一个国王,但是一个国王相邻的八个格子(上下左右,左上,左下,右上,右下)都不能有其他国王,求出在n*n的棋盘放k个国王的方案数
题解:
状压DP,数据范围n<=9,显然可以压,f[i][j][k]表示棋盘第i行放置国王的状态位j时,总共放了k个国王的方案数
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; LL bin[11]; LL f[10][(1<<9)-1][110]; LL v[(1<<9)-1]; LL r[(1<<9)-1]; int main() { int n,k; scanf("%d%d",&n,&k); bin[1]=1;for(int i=2;i<=n;i++) bin[i]=bin[i-1]<<1; LL mx=(1<<n)-1; memset(v,0,sizeof(v)); int vn=0; memset(f,0,sizeof(f)); memset(r,0,sizeof(r)); for(int x=0;x<=mx;x++) { if(((x<<1)&x)==0) { v[++vn]=x; for(int i=1;i<=n;i++) if((bin[i]&x)!=0) r[vn]++; f[1][x][r[vn]]=1; } } for(int i=2;i<=n;i++) { for(int p=1;p<=vn;p++) { for(int q=1;q<=vn;q++) { if((v[p]&v[q])==0&&((v[q]<<1)&v[p])==0&&((v[q]>>1)&v[p])==0&&r[p]+r[q]<=k) { for(int kk=r[q];kk<=k-r[p];kk++) { f[i][v[p]][r[p]+kk]+=f[i-1][v[q]][kk]; } } } } } LL ans=0; for(int i=1;i<=vn;i++) ans+=f[n][v[i]][k]; printf("%lld ",ans); return 0; }