bzoj 1087: [SCOI2005]互不侵犯King

来源:互联网 发布:淘宝代销和经销的区别 编辑:程序博客网 时间:2024/05/22 14:32

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2600  Solved: 1540
[Submit][Status][Discuss]

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

[Submit][Status][Discuss]


#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#define N 10#define ll long long using namespace std;int n,m,tot,cnt[1<<N];bool line[1<<N],ok[1<<N][1<<N];ll f[N][N*N][1<<N];int main(){scanf("%d%d",&n,&m);tot=(1<<n)-1;//每一行总共的状态数 for (int i=0;i<=tot;i++) if (((i>>1)&i)==0)//右移一位,所有位置就全都差开了一位,如果这是有一个位置运算后的值为1,则说明有两个国王挨在一起了   {  for (int j=i;j>0;j>>=1)//统计当前状态中放置了多少个国王    cnt[i]+=(j&1);  line[i]=true;//当前状态合法   }for (int i=0;i<=tot;i++) if (line[i])  {  for (int j=0;j<=tot;j++)   if (line[j])    if ((i&j)==0&&((i>>1)&j)==0&&((j>>1)&i)==0)//判断两行之间是否冲突      ok[i][j]=true;  }for (int i=0;i<=tot;i++) if (line[i])  f[1][cnt[i]][i]=1;//f[i][j][k]表示放置到第I行,一共放置了J个国王,当前行的状态为K for (int p=2;p<=n;p++) for (int i=0;i<=tot;i++)  if (line[i])   for (int j=0;j<=tot;j++)    if (line[j])     if (ok[i][j])      for (int k=cnt[i];k+cnt[j]<=m;++k)       f[p][k+cnt[j]][j]+=f[p-1][k][i];ll ans=0;for (int i=0;i<=tot;++i) ans+=f[n][m][i];cout<<ans<<endl;}


0 0
原创粉丝点击