bzoj1087: [SCOI2005]互不侵犯King 状压dp
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
第一眼看成k皇后问题了,仔细一看原来是状压dp,dp【i】【j】【k】i是滚动数组压缩形式,j是上一层的状态,k是已经用过的国王数,那么转移很明显,从上一层转移到下一层,枚举两层的所有状态看会不会冲突,不冲突就能转移,d[now][j][num+k]+=dp[pre][i][k],now是这一层用过的国王数。,最后记录满足条件的k即可,复杂度O(n^2*2^2n),大约是1e8
/************************************************************** Problem: 1087 User: walfy Language: C++ Result: Accepted Time:572 ms Memory:4604 kb ****************************************************************/ //#pragma comment(linker, "/stack:200000000") //#pragma GCC optimize("Ofast,no-stack-protector") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") //#pragma GCC optimize("unroll-loops") #include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pi acos(-1.0) #define ll long long #define vi vector<int> #define mod 1000000007 #define C 0.5772156649 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define pil pair<int,ll> #define pli pair<ll,int> #define pii pair<int,int> #define cd complex<double> #define ull unsigned long long #define base 1000000000000000000 #define fio ios::sync_with_stdio(false);cin.tie(0) using namespace std; const double g=10.0,eps=1e-12; const int N=1000+10,maxn=100000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f; ll dp[2][N][200+10]; int main() { int n,k; scanf("%d%d",&n,&k); int now=1,pre=0; for(int i=0;i<(1<<n);i++) { int num=0,ok=1; for(int j=0;j<n;j++) { if((i>>j)&1)num++; if(j&&((i>>(j-1))&1)&&((i>>j)&1)){ok=0;break;} } if(ok) { dp[pre][i][num]++; // printf("%d %d %d\n",i,num,dp[pre][i][num]); } } for(int _=2;_<=n;_++) { memset(dp[now],0,sizeof dp[now]); for(int i=0;i<(1<<n);i++)//last { for(int j=0;j<=k;j++)//last k { for(int u=0;u<(1<<n);u++) { if(dp[pre][i][j]==0)continue; int num=0,ok=1; for(int v=0;v<n;v++) { int st=(u>>v)&1,last=(i>>v)&1; if((u>>v)&1)num++; if(st&&last) { ok=0; break; } if(v>0) { last=(i>>(v-1))&1; if(st&&last){ok=0;break;} last=(u>>(v-1))&1; if(st&&last){ok=0;break;} } if(v<n-1) { last=(i>>(v+1))&1; if(st&&last){ok=0;break;} last=(u>>(v+1))&1; if(st&&last){ok=0;break;} } } if(ok) { // printf("last = %d ++ last k = %d ++ now = %d dp[pre][i][j] = %d ++ num+j = %d\n",i,j,u,dp[pre][i][j],num+j); dp[now][u][num+j]+=dp[pre][i][j]; // printf("%d %d %d %d\n",now,u,num+j,dp[now][u][num+j]); } } } } swap(now,pre); } ll ans=0; for(int i=0;i<(1<<n);i++) ans+=dp[pre][i][k]; printf("%lld\n",ans); return 0; }