• P1044 栈题解


    题目传递门

    一、深搜

    别的也不会,一个深搜走天下!深搜我们主要关心的是下一步噢~

    怎么个深搜法呢?我们模拟一下,有一个装个顺序号小球的队列,一个个准备放到一个栈里。一共几下面几种场景:
    1、队列为空,栈为空。
    这种场景的下一步就只能是“游戏终止”,而“游戏终止”时我们应该方案数+1。

    2、队列为空,栈不空。
    这种场景下下一步只能是栈弹出一个,一直到弹空了为止,也就是,方案数+1。

    3、队列不空,栈为空。
    这种场景下下一步只能是队列出来一个,栈进去一个,场景变为“队列-1,栈+1”。

    4、队列不空,栈不空。
    这种场景下下一步有点麻烦,可以是队列-1,栈+1;也可以是队列不动,栈-1。

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long LL;
    
    int n;
    // i 表示队列里还有几个待排的数,
    // j 表示栈里有 j 个数,dfs(i,j)表示此时的情况数
    // 不重不漏的描述了所有情况
    
    LL dfs(int i, int j) {
        LL ans = 0;
        //(1)队列空,栈空
        if (i == 0 && j == 0)ans += 1; //这是递归出口,增加一种方法
        //(2)队列空,栈不空
        if (i == 0 && j > 0) ans += 1; //只能一个个蹦出去啦~
        //(3)队列不空,栈空
        if (i > 0 && j == 0) ans += dfs(i - 1, j + 1); //从队列中取一个,放入到栈中
        //(4)队列不空,栈不空
        if (i > 0 && j > 0) ans += dfs(i, j - 1) + dfs(i - 1, j + 1);//有两种选择,一是队列不动,栈中出去一个;另一种是队列取一个,放入栈中
        return ans;
    }
    
    int main() {
        cin >> n;
        printf("%lld", dfs(n, 0));
        return 0;
    }
    

    结果5个测试点,过了4个,最后一个TLE了~

    2、记忆化搜索

    我们观察到,上面的代码之所以超时,根源是因为这个和前面“过河卒”一样,存在大量重复计算,到达某个点后,这个点再出发都是重复的。可以考虑使用反向思维用递推!当然,本题也可以使用记化搜索来解决:

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 20;
    typedef long long LL;
    
    int n;
    // 定义一个二维数组f[i,j]f[i,j],用下标 i 表示队列里还有几个待排的数,
    // j 表示栈里有 j 个数,f[i,j]表示此时的情况数
    // 不重不漏的描述了所有情况
    LL f[N][N]; //记忆化搜索
    
    LL dfs(int i, int j) {
        //算过
        if (f[i][j]) return f[i][j];
        //(1)队列空,栈空
        if (i == 0 && j == 0) f[i][j] += 1; //这是递归出口,增加一种方法
        //(2)队列空,栈不空
        if (i == 0 && j > 0) f[i][j] += 1;//只能一个个蹦出去啦~
        //(3)队列不空,栈空
        if (i > 0 && j == 0) f[i][j] += dfs(i - 1, j + 1);//从队列中取一个,放入到栈中
        //(4)队列不空,栈不空
        if (i > 0 && j > 0) f[i][j] += dfs(i, j - 1) + dfs(i - 1, j + 1);//有两种选择,一是队列不动,栈中出去一个;另一种是队列取一个,放入栈中
        return f[i][j];
    }
    
    int main() {
        cin >> n;
        printf("%lld", dfs(n, 0));
        return 0;
    }
    

    使用记化搜索后,成功AC本题。

    3、递推

    既然可以使用递推,那么递推的步骤和思路是什么样的呢?
    1、边界值
    一定要有小的方向的边界!!!而且特别要注意元素个数是0的情况!!!

    2、求啥就定义啥,按需求定义数组
    (dp[i])代表了(i)个元素的所有出管方法数量。

    3、对(i)个元素的大场景进行子集合的切分,要不重不漏,一般是按最后一个不相同的点切分。
    本题是按最后一个出栈元素进行划分开,分情况讨论。

    对于从(j in [1 , i])来讲,第(j)个小球是最后一个出栈的,那么在它之前有(j-1)个元素先入栈,先出栈;在它之后,有(n-j)个小球后入栈,后出栈。那么,以它为最后一个出栈的方案数量就是(dp[i]=dp[j-1] imes dp[i-j])(乘法原理)
    对于(i)个小球来讲,就是如下的伪代码示意:

      for(int j=1;j<=i;j++)
         dp[i]+=dp[j-1]*dp[i-j];//所有子集合的方案数量和,加法原理
    

    完整代码

    #include <bits/stdc++.h>
    
    using namespace std;
    // h[i]:i个元素一共有h[i]种出管方式
    // 0个元素,只有一种情况,这种情况就是啥也不出,啥也不出也算是一种场景。
    // 1个元素,只有一种情况,就是出队列,进栈,出栈。
    int n, dp[20] = {1, 1};
    
    
    int main() {
        cin >> n;
    
        for (int i = 2; i <= n; i++)
            for (int j = 1; j <= i; j++)//最后出栈的元素假设是j
                dp[i] += dp[j-1] * dp[i - j];//所有的可能性加在一起
    
        printf("%d", dp[n]);
        return 0;
    }
    

    4、卡特兰数解法

    为什么会想到用卡特兰数公式来解这道题呢?
    超棒的讲解
    https://www.bilibili.com/video/BV1nE411A7ST?from=search&seid=2618099886973795159

    #include <bits/stdc++.h>
    
    // 超棒的讲解
    // https://www.bilibili.com/video/BV1nE411A7ST?from=search&seid=2618099886973795159
    using namespace std;
    
    /**
    如果n=1 1
    如果n=2 2
    如果n=3 5
    如果n=4 14
    如果n=5 42
    如果n=6 132
    如果n=7 429
    如果n=8 1430
    如果n=9 4862
    如果n=10 16796
    如果n=11 58786
    如果n=12 208012
    如果n=13 742900
    如果n=14 2674440
    如果n=15 9694845
    如果n=16 35357670
    如果n=17 129644790
    如果n=18 477638700
    卡特兰数!!!
     */
    int catalan(int n) {
        if (n == 0 || n == 1) return 1;
        int res = 0;
        for (int i = 1; i <= n; i++) res += catalan(i - 1) * catalan(n - i);
        return res;
    }
    
    int main() {
        int n;
        cin >> n;
        cout << catalan(n) << endl;
        return 0;
    }
    
  • 相关阅读:
    内存对齐
    C++中构造函数
    计算机视觉领域的大牛主页
    各种银行卡的收费情况
    常识
    毕业生必须知道
    计算机视觉领域资料
    人际关系
    生活常识
    可使用在项目的web gantt甘特图有哪些?
  • 原文地址:https://www.cnblogs.com/littlehb/p/15019135.html
Copyright © 2020-2023  润新知