• Catalan数


    【问题描述】对于一个栈,已知元素的进栈序列,判断一个由栈中所有元素组成的排列的出栈序列。

    有N个数,则代表入栈序列为1,2,3,4,5...,N。求所有可能的出栈序列和总数。

    代码如下

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<string>
    #include<stdio.h>
    using namespace std;
    int N = -1;
    int sum = 0;;
    //递归算法
    //count:当前已经入栈的元素个数
    //seq:当前栈
    //result:出栈序列,从左到右为出栈序列
    void printValidSequence(int count,vector<int> seq,vector<int> result){
        if (count == N){
            result.insert(result.end(), seq.rbegin(), seq.rend());
            for (int i = 0; i < result.size(); ++i){
                cout << result[i];
            }
            cout << endl;
            sum++;
            return;
        }
        vector<int> tmp(seq.begin(), seq.end());
        seq.push_back(++count);    //下一个元素入栈
        printValidSequence(count, seq, result);
        if (!tmp.empty()){         //当前元素出栈出栈
            result.push_back(tmp.back());
            tmp.pop_back();
            printValidSequence(count-1, tmp, result);
        }    
    }
    //非递归算法
    //递归算法
    //count:当前已经入栈的元素个数
    //seq:当前栈
    //result:出栈序列,从左到右为出栈序列
    class node{
    public:
        vector<int> seq;
        vector<int> result;
        int count;
        node(){
            seq.clear();
            result.clear();
            count = 0;
        }
        void print(){
            result.insert(result.end(), seq.rbegin(), seq.rend());
            for (int i = 0; i < result.size(); ++i){
                cout << result[i];
            }
            cout << endl;
        }
        void add(){
            result.push_back(seq.back());
            seq.pop_back();
        }
        void push(){
            seq.push_back(++count);
        }
    };
    void printValidSequence(int N){
        vector<node> STACK;
        STACK.push_back(node());
        while (true){
            if (STACK.empty()){
                break;
            }
            node tmp = STACK.back(); //出栈
            node tmp2 = tmp;//入栈(=是拷贝)
            STACK.pop_back();
            if (tmp.count == N){
                tmp.print();
                sum++;
            }
            else{
                if (!tmp.seq.empty()){
                    tmp.add();
                    STACK.push_back(tmp);
                }
                tmp2.push();
                STACK.push_back(tmp2);
            }
        }
    }
    int main(){
        cin >> N;
        vector<int> seq;
        vector<int> result;
        printValidSequence(0, seq, result); //递归算法 
        cout << "总数为" << sum << endl;
        sum = 0;
        printValidSequence(N);  //非递归算法
        cout << "总数为" << sum << endl;
        system("pause");
        return 0;
    }

    也可以用Catalan数求解。

    h(n)=h(0)h(n-1)+h(1)h(n-2)+...+h(n-1)h(0)  h(0)=h(1)=1  <=> h(n)=C(2n,n)*(1/(1+n))  (C是组合符号)

    对于本道题:

        首先,我们设h(n)=序列个数为n的出栈序列种数。我们假定,最后出栈的元素为k,显然,k取不同值时的情况是相互独立的,也就是求出每种k最后出栈的情况数后可用加法原则,由于k最后出栈,因此,在k入栈之前,比k小的值均出栈,此处情况有f(k-1)种,而之后比k大的值入栈,且都在k之前出栈,因此有f(n-k)种方式,由于比k小和比k大的值入栈出栈情况是相互独立的,此处可用乘法原则,f(n-k)*f(k-1)种,求和便是Catalan递归式。

        因此种类数是h(n)=C(2n,n)*(1/(1+n))

    本题和另外一道题也是等价的:

         一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果他
    从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?
    我们使用深度优先搜索来完成这道题目;
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<string>
    #include<stdio.h>
    using namespace std;
    int N = -1;
    int sum = 0;
    class node{
    public:
        int x;
        int y;
        int dir;  //1,2分别代表右和上
        node(){
            x = 0;
            y = 0;
            dir = 0;
        }
        node(int _x,int _y,int _dir){
            x = _x;
            y = _y;
            dir = _dir;
        }
        int sum(){
            return x + y;
        }
        bool compare(){
            if (x > y){
                return true;
            }
            else{
                return false;
            }
        }
    };
    void searchDest(int N){
        vector<node> STACK;
        STACK.push_back(node());
        while (true){
            if (STACK.empty()){
                break;
            }
            else{
                node topNode = STACK.back();
                if (topNode.sum() == 2 * N){ //到达终点
                    sum++;
                    vector<int> stack1;//模拟出入栈,得到输出序列,向右走为入栈,向上走为出栈
                    vector<int> result;
                    for (int i = 1; i < STACK.size(); ++i){                    
                        if (STACK[i].y - STACK[i - 1].y>0){                        
                            result.push_back(stack1.back());
                            stack1.pop_back();
                        }
                        else{
                            stack1.push_back(STACK[i].x);
                        }
                    }
                    for (int i = 0; i < result.size(); ++i){
                        cout << result[i];
                    }
                    cout << endl;
                    STACK.pop_back();
                }
                else{
                    if (topNode.dir == 0){
                        STACK.back().dir++;
                        if (topNode.x < N){
                            STACK.push_back(node(topNode.x + 1, topNode.y, 0));;//向右走
                        }
                    }
                    else if (topNode.dir == 1){
                        STACK.back().dir++;
                        if (topNode.compare()){
                            STACK.push_back(node(topNode.x, topNode.y + 1, 0)); //向上走
                        }
                    }
                    else if (topNode.dir == 2){
                        STACK.pop_back();
                    }
                }
            }
        }
    }
    int main(){
        cin >> N;
        searchDest(N);
        cout << "总数为:" << sum << endl;
        system("pause");
        return 0;
    }

    还有一个问题是,给出一个序列判断该序列是否为合法的输出序列:

    比如输入序列是:1,2,3,4,5

    序列53421就是合法序列:

    有如下的判定定理:
    对于出栈序列中的每一个数字,在它后面的、比它小的所有数字,一定是按递减顺序排列的。<=> 该输出序列是合法的

     
  • 相关阅读:
    docker命令
    IntelliJ IDEA设置JVM运行参数
    SpringResourceBundleMessageSource示例(转)
    通过ApplicationContextAware加载Spring上下文环境(转)
    @ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常(转)
    SpringBoot学习(十一)创建自己的自动配置和Kotlin支持
    SpringBoot学习(十)Spring集成、会话、(监视和管理JMX)、WebSockets和web服务
    BindingResult不能获取错误对象
    SpringBoot学习(九)使用JTA的分布式事务、Hazelcast、Quartz调度器和任务执行和调度
    Maven项目中pom文件分析
  • 原文地址:https://www.cnblogs.com/codeDog123/p/6659846.html
Copyright © 2020-2023  润新知