zoukankan      html  css  js  c++  java
  • [SCOI2005][BZOJ1087] 互不侵犯King

    1087: [SCOI2005]互不侵犯King

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 1963  Solved: 1165
    [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
     
    接触的第一道状压DP,开始感觉是暴搜的样子,突然发现状态略多……
    于是上网开始翻题解,作为一个从没学过状压的蒟蒻,看着题解的代码也不知道是什么东西……于是静心研究了一片题解。最后看懂了代码,也通过此题了解了状压的思想。
    f[i][j][now]表示第i行,从头到现在已经放了j个马,当前行的状态为now(用二进制表示)时的方案数,可以从上一行转移来。f[i][j][now]=Sigma(f[i-1][j-cnt[now]][x]),x表示上一层的状态数,cnt表示now状态的马的数量。
    由于方案略多,而且我们发现有一些冗余的状态,因为马不能相邻摆放,若用1表示放马,0表示不放马,则11这种情况是不合法的,这样在转移时会有许多不必要的麻烦。
    在做dp之前,先用dfs进行预处理,即枚举出在一行上放马的所有合法状态(暴力dfs就好了),然后枚举任意两种状态可否作为相邻两行来摆放,即有无上下都是马,左上右下都是马,左下右上都是马这几种情况(用&位运算处理),用二维数组存下这些状态之间的关系。
    最后就是四层for循环进行DP了,因为进行了强大的预处理,O(1)转移就毫无压力了。
     
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    int n,m,k,stay[101],cnt[101];
    long long ans,f[10][101][101];
    bool map[101][101];
    void dfs(int p,int put,int num)
    {
        stay[++m]=num;
        cnt[m]=p;
        if (p>=k||p>=(n+1)/2) return;
        for (int i=put+2;i<=n;i++) dfs(p+1,i,num+(1<<(i-1)));
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        m=0;
        dfs(0,-1,0);
        for (int i=1;i<=m;i++)
            for (int j=1;j<=m;j++)
                map[i][j]=map[j][i]=((stay[i]&stay[j])||((stay[i]<<1)&stay[j])||((stay[i]>>1)&stay[j]))?0:1;
        for (int i=1;i<=m;i++) f[1][cnt[i]][i]=1ll;
        for (int i=2;i<=n;i++)
            for (int j=0;j<=k;j++)
                for (int now=1;now<=m;now++)
                {
                    if (cnt[now]>j) continue;
                    for (int l=1;l<=m;l++)
                        if (map[now][l]&&cnt[l]+cnt[now]<=j) f[i][j][now]+=f[i-1][j-cnt[now]][l];
                }
        ans=0;
        for (int i=1;i<=m;i++) ans+=f[n][k][i];
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    Python return语句用法分析
    set built-in function
    dict built-in function
    String bulit-in function
    tuple built-in function
    Pyhton:List build-in function
    Python之如果添加扩展包
    关于编辑器
    attachEvent和addEventListener详解
    jquery异步调用页面后台方法
  • 原文地址:https://www.cnblogs.com/ws-fqk/p/4635960.html
Copyright © 2011-2022 走看看