BZOJ 1087 [SCOI2005] 互不侵犯King

来源:互联网 发布:linux怎么读音是什么 编辑:程序博客网 时间:2024/06/04 19:44

Description

  在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

  方案数。

Sample Input

3 2

Sample Output

16

HINT

Source

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

状压DP~

大清早的不太清醒……先是把国王走法看成了国际象棋里面皇后的走法想到吐血……然后数组又开小了RE到飞起……不过话说如果是皇后走法的话怎么做呢?

先预处理出每一种可能的情况cas[](只考虑单行不能相邻),然后DP,用f[k][i][j]表示枚举第i行,状态是k,已经放了(包含i行)j颗棋子的种类数,然后就像前面几道那样DP就好了~

另外注意f数组和ans都要开成long long!


#include<cstdio>#include<iostream>using namespace std;#define ll long longint n,m,cas[520],num[520],tot;ll f[520][10][101],ans;bool che(int u){return !(u&(u>>1));}bool che2(int u,int v){return !(u&v) && !(u&(v<<1)) && !(u&(v>>1));}int cal(int u){int totnum=0;for(int i=0;i<=9;i++)  if(u&(1<<i)) totnum++;return totnum;}int main(){scanf("%d%d",&n,&m);for(int i=0;i<(1<<n);i++)  if(che(i))  {  cas[++cas[0]]=i;num[cas[0]]=cal(i);  f[cas[0]][1][num[cas[0]]]=1;  }for(int i=2;i<=n;i++)  for(int k=1;k<=cas[0];k++)    for(int j=1;j<=cas[0];j++)    if(che2(cas[k],cas[j]))      for(int z=num[j];z+num[k]<=m;z++) f[k][i][z+num[k]]+=f[j][i-1][z];for(int i=1;i<=cas[0];i++) ans+=f[i][n][m];printf("%lld\n",ans);return 0;}


1 0