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;
    }
  • 相关阅读:
    LeetCode对撞指针汇总
    167. Two Sum II
    215. Kth Largest Element in an Array
    2018Action Recognition from Skeleton Data via Analogical Generalization over Qualitative Representations
    题解 Educational Codeforces Round 84 (Rated for Div. 2) (CF1327)
    题解 JZPKIL
    题解 八省联考2018 / 九省联考2018
    题解 六省联考2017
    题解 Codeforces Round #621 (Div. 1 + Div. 2) (CF1307)
    题解Codeforces Round #620 (Div. 2)
  • 原文地址:https://www.cnblogs.com/ws-fqk/p/4635960.html
Copyright © 2011-2022 走看看