1087: [SCOI2005]互不侵犯King

来源:互联网 发布:知乎 中美军演 编辑:程序博客网 时间:2024/05/16 03:18

题目链接

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

题解:f[i][j][k]ijik

设计函数判断一行/两行可行

一行可行只需要判断二进制是否有相邻的1
两行还需要判上下相邻……参悟一下……

处理出第一行的可行情况

lttmp=cnt(l)
f[i][j][l]+=f[i1][jtmp][t]

我的收获:二进制强啊

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int n,m,k;long long ans,f[15][100][1024];inline bool ok(int x,int y){return !((x&(y<<1))||(x&(y>>1))||(x&y));}//判断两行可行,左右上下 inline bool ck(int x){return !((x&(x<<1))||(x&(x>>1)));}//判断一行状态可行 inline int cnt(int x){int i,ret=0;for(i=x;i;i-=i&(-i),ret++);return ret;}//返回x二进制中1的个数 void work(){    for(int i=2;i<=n;i++)        for(int j=0;j<=m;j++)            for(int l=0;l<=k;l++)                if(ck(l)&&j>=cnt(l))                {                    int tmp=cnt(l);                    for(int t=0;t<=k;t++)                        if(ck(t)&&ok(l,t)) f[i][j][l]+=f[i-1][j-tmp][t];                }    for(int i=0;i<=k;i++) ans+=f[n][m][i];    printf("%lld\n",ans);}void init(){    scanf("%d%d",&n,&m);    k=(1<<n)-1;    for(int i=0;i<=k;i++) if(ck(i)) f[1][cnt(i)][i]=1;}int main(){    init();    work();    return 0;}
原创粉丝点击