• [SCOI2005] 互不侵犯


    传送门:>Here<

    给出一个n*n的棋盘($n leq 9$),放$k$个骑士,每个骑士可以攻击相邻的八个方向。问所有骑士互不侵犯的摆放方案数。

    解题思路

    决策问题可以通过搜索解决,而DP就是记忆化搜索。而在这里,我们直接考虑整排的决策比较方便。

    在搜索时我们需要利用到哪些信息来完成决策?显然能影响到当前决策的有上一排的各个骑士位置,还能用几个骑士。而上一排的各个骑士位置是一个布尔数组,转化为DP的话这就成为了DP的一个状态。数据范围小的时候,我们是可以直接将布尔数组转为二进制作为状态的。我们称这种DP方法为状态压缩DP。

    分析DP的时间复杂度,一般是状态数量乘上转移的复杂度。这里状态数是$O(2^nnk)$,而转移时枚举上一行状态$O(2^n)$,故总复杂度为$O(2^{2n}n^3)$。

    这样的复杂度是过不了的。而事实上,一行内的合法状态数远不足$2^n$,所以我们可以预处理出每一行的合法状态数,这样就能过了。

    $Code$

    /*By QiXingzhi*/
    #include <cstdio>
    #define  N  (4010)
    #define  r  read()
    #define  INF   (0x3f3f3f3f)
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    typedef long long ll;
    #define  int ll
    using namespace std;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar();
        return x * w;
    }
    int n,K,tot,ans;
    int sta[N],num[N],f[12][N][144];
    void Dfs(int x, int cur, int sum){
        if(x >= n){
            ++tot;
            sta[tot] = cur;
            num[tot] = sum;
            f[1][tot][sum] = 1;
            return;
        }
        Dfs(x+1,cur,sum);
        Dfs(x+2,cur+(1<<x),sum+1);
    }
    #undef int
    int main(){
    #define  int ll
        n=r,K=r;
        Dfs(0,0,0);
        for(int i = 2; i <= n; ++i){
            for(int j = 1; j <= tot; ++j){
                for(int k = 1; k <= tot; ++k){
                    if(sta[j] & sta[k]) continue;
                    if(sta[j] & (sta[k] << 1)) continue;
                    if(sta[j] & (sta[k] >> 1)) continue;
                    for(int s = num[j]; s <= K; ++s){
                        f[i][j][s] += f[i-1][k][s-num[j]];
                    }
                }
            }
        }
        for(int i = 1; i <= tot; ++i) ans += f[n][i][K];
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    冒泡排序
    【leetcode 简单】第二十二题 对称二叉树
    【leetcode 简单】第二十一题 相同的树
    【leetcode 简单】第二十七题 二叉树的最小深度
    【leetcode 简单】第二十三题 二叉树的最大深度
    python 版本zabbix_sender
    C语言二分查找
    【leetcode 简单】第二十题 合并两个有序数组
    【leetcode 简单】第十九题 删除排序链表中的重复元素
    【leetcode 简单】第十八题 爬楼梯
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9264853.html
Copyright © 2020-2023  润新知