您的位置:首页 > 其它

【SCOI2005】【BZOJ1087】互不侵犯King

2015-08-28 09:35 337 查看
我天生不喜欢Dp就算你是状压DP…

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…

设f[i][j][k]为到了第i行已经放了k个国王,当前行状态为k

二进制表示国王的放置位置.

然后可以进行O(nk22n)O(nk2^{2n})转移

最后求一个sum就是答案

[code]#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 1024
#define LL long long
using namespace std;
int n,k;
LL ans,f[15][100][MAXN];
inline bool check(int x,int y)
{
    return !((x&(y<<1))||(x&(y>>1))||(x&y));
}
inline bool Check(int x)
{
    return !((x&(x<<1))||(x&(x>>1)));
}
inline int get(int x)
{
    int ret=0;
    for (int i=x;i;i>>=1)
        if (i&1)    ret++;
    return ret;
}
int main()
{
    scanf("%d%d",&n,&k);
    int Max=(1<<n)-1;
    for (int i=0;i<=Max;i++)    
        if (Check(i))   f[1][get(i)][i]=1;
    for (int i=2;i<=n;i++)
        for (int j=0;j<=k;j++)
            for (int l=0;l<=Max;l++)
                if (Check(l)&&j>=get(l))
                {
                    int tmp=get(l);
                    for (int t=0;t<=Max;t++)
                        if (Check(t)&&check(l,t))   f[i][j][l]+=f[i-1][j-tmp][t];
                }
    for (int i=0;i<=Max;i++)
        if (Check(i))   ans+=f
[k][i];
    printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: