题面:https://www.luogu.org/problemnew/show/P1896
大意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
状压DP
用二进制表示当前状态。
1表示有,0表示无。
那么这个题的f[ i ][ j ][ w ]表示在第 i 行,状态为 j ,用了 w 个国王。
方程见代码。
其中bitset为二进制数位。
a.count()表示二进制数中有多少个1。
vis[ ]数组为符合条件的一行的状态。
代码如下:
#include<bits/stdc++.h> #define int long long #define rr register using namespace std; int n,m,ans=0; bool vis[1<<9]; int f[10][1<<9][90],g[1<<9]; signed main() { scanf("%lld%lld",&n,&m); for(rr int i=0;i<(1<<n);i++){ if(!(i&(i<<1)) && !(i&(i>>1))) vis[i]=1; bitset <9> a(i); g[i]=a.count(); if(vis[i]) f[1][i][g[i]]=1; } for(rr int i=2;i<=n;i++) for(rr int j=0;j<(1<<n);j++) if(vis[j]) for(rr int k=0;k<(1<<n);k++)///? if(vis[k] && !(j&(k<<1)) && !(j&(k>>1)) && !(j&k)) for(rr int w=0;w+g[k]<=m;w++) f[i][k][w+g[k]]+=f[i-1][j][w]; for(rr int i=0;i<(1<<n);i++) ans+=f[n][i][m]; printf("%lld ",ans); // system("pause"); return 0; }
因为数据加强,记得开 long long。