BZOJ 1087 [SCOI2005]互不侵犯King(状压DP)
题意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。n<=9
思路:状压dp,dp[i][j][k]为前i行放了j个,第i行状态为k
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 998244353; const int maxn = 2e6+100; const int maxm = 2e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); ll dp[20][200][2000]; int n, k; int num[2000]; int ys[2000]; int main(){ mem(dp, 0); mem(ys, 0); scanf("%d %d", &n, &k); for(int i = 0; i < (1<<n); i++){ int p = i; int cnt = 0; while(p){ if(p&1)cnt++; p>>=1; } num[i]=cnt; } for(int i = 0; i < (1<<n); i++){ if(((i<<1)&i) ||((i>>1)&i)){ continue; } ys[i] = 1; dp[1][num[i]][i]=1; } for(int i = 2; i <= n; i++){ for(int j = 0; j <= k; j++){ for(int p = 0; p < (1<<n); p++){//now if(!ys[p])continue; if(num[p]>j)continue; for(int x = 0; x < (1<<n); x++){//last status from i-1 if(!ys[x])continue; if((p&x)||((p<<1)&x)||(p>>1)&x)continue; dp[i][j][p] += dp[i-1][j-num[p]][x]; } } } } ll ans = 0; for(int i = 0; i < (1<<n); i++){ ans += dp[n][k][i]; } printf("%lld", ans); return 0; }