BZOJ1087 [SCOI2005]互不侵犯King 状压dp

来源:互联网 发布:泰坦尼克号真相 知乎 编辑:程序博客网 时间:2024/05/16 14:12

给定一个n*n的网格,问恰好摆放K个国王的方案数。n,m<=9.

显然状压dp.

因为国王最多只能向下影响1行.

预处理出每个状态为i的棋子数cnt[i],当前状态是否合法c0[i],前一行状态为j时两个状态能否转移的c[i][j].

所以设 f[i][j][k]表示摆到第i行,已经摆了j个棋子,当前行的状态为k的方案数.

则f[i][j][k]=Σf[i-1][j-cnt[k]][l].(c0[k]&&c0[l]&&c[k][l])

最后Σf[n][K][i]即为答案.

#include<bits/stdc++.h>#define LL long long#define clr(x,i) memset(x,i,sizeof(x))using namespace std;const int N=10;int n,K,r;LL f[N][N*N][520];int c0[520],c[520][520],cnt[520];void presolve(){r=1<<n;int s;for(int i=0;i<r;i++){if((i&(i>>1))!=0)continue;//这个地方少打一个括号,坑了好久了!!...c0[i]=1;for(int j=0;(1<<j)<=i;j++)  if(i&(1<<j))cnt[i]++;}for(int i=0;i<r;i++)  for(int j=0;j<r;j++)    if(c0[i]&&c0[j]){    if( (i&j)==0 && ((i>>1)&j)==0 && (i&(j>>1))==0)      c[i][j]=1;    }}int main(){scanf("%d%d",&n,&K);presolve();for(int i=0;i<r;i++)  if(c0[i])f[1][cnt[i]][i]=1;for(int t=1;t<n;t++)  for(int j=0;j<r;j++)if(c0[j])    for(int k=0;k<r;k++)if(c0[k])      {        if(!c[j][k])continue;        for(int i=cnt[j];i+cnt[k]<=K;i++)          f[t+1][i+cnt[k]][k]+=f[t][i][j];      }LL ans=0;for(int i=0;i<r;i++)  ans+=f[n][K][i];printf("%lld",ans);return 0;}



阅读全文
0 0
原创粉丝点击