zoukankan      html  css  js  c++  java
  • noip2008双栈排序

    双栈排序

    【题目描述】 

    Tom最近在研究一个有趣的排序问题。如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序。

    操作a
    如果输入序列不为空,将第一个元素压入栈S1
    操作b
    如果栈S1不为空,将S1栈顶元素弹出至输出序列
    操作c
    如果输入序列不为空,将第一个元素压入栈S2
    操作d
    如果栈S2不为空,将S2栈顶元素弹出至输出序列

    如果一个1~n的排列P可以通过一系列操作使得输出序列为1,2,…,(n-1),n,Tom就称P是一个“可双栈排序排列”。例如(1,3,2,4)就是一个“可双栈排序序列”,而(2,3,4,1)不是。

    将(1,3,2,4)排序的操作序列:<a,c,c,b,a,d,d,b>

    当然,这样的操作序列有可能有几个,对于上例(1,3,2,4),<a,c,c,b,a,d,d,b>是另外一个可行的操作序列。

    Tom希望知道其中字典序最小的操作序列是什么。

    【输入】

    第一行是一个整数n。

    第二行有n个用空格隔开的正整数,构成一个1~n的排列。

    【输出】

    输出文件共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;
    否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。

    【题解分析】

    二分图即位所有点可以分为两个独立点集。

    简单来说就是看是否能把图中的每个点分成两份,连上他们之间的边,不存在三个点之间互相连起的边构成三角形。

    而双栈则是要把图中的点都分成两份,看是否满足二分图的性质。

    把能进同一个栈的两个元素之间连一条边。

    对于i<j<k,使得S[k]<S[i]<S[j].则需要两个栈。若逐一查找,O(n^3)显然不够优秀。

    Get优化:动态规划。

    能将枚举k转化为O(1)的算法。

    这里f[i] = min{s[1],s[2],…,s[i]}转移方程是:f[i] = min{s[i],f[i+1]}.注意要从后往前枚举。

    整个算法复杂度是O(n^2).

    关于染色

     两种颜色,y代表与之相连的一条边,为不构成三角形,y与x应染上不同的颜色。

    如果y与x染成不同颜色返回值为0,即不可能,那么y与x不同颜色也不可能。

    如果y染成与x相同的颜色,返回值为0.

    否则返回值为1

     

    #include<bits/stdc++.h>
    using namespace std;
    #define INF 1e9
    const int maxn = 1e3+5;
    int n,len,s[maxn],to[maxn],v[maxn];
    int s1[maxn],s2[maxn],f[maxn];
    struct edge{int y,next;}e[2000005];
    inline int read(){
        int x = 0,f = 1; char ch = getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f = -1;ch = getchar();}
        while(ch>='0'&&ch<='9'){x = x*10 + ch-'0';ch = getchar();}
        return x*f;
    }
    void insert(int xx,int yy){
        e[++len].next = to[xx];
        to[xx] = len;
        e[len].y = yy;
    }
    bool color(int x,int cl){
        v[x] = cl;
        for(int i = to[x]; i;i = e[i].next){
            int y = e[i].y;
            if(!v[y]){
                if(!color(y,3-cl)) return 0;
            }
            else if(v[y] == cl) return 0;
        }
        return 1;
    }
    void init(){
        n = read();
        for(int i = 1;i <= n; i++)    s[i] = read(); 
        f[n+1] = INF;
    }
    int main(){
        init();
    //    memset(v,0,sizeof(v));
        for(int i = n; i > 0; i--) f[i] = min(f[i+1],s[i]);
        for(int i = 1;i <= n; i++)
            for(int j = i+1;j <= n; j++)
                if(s[i]<s[j]&&f[j+1]<s[i]) insert(i,j),insert(j,i);
        for(int i = 1;i <= n; i++)
            if(!v[i])
                if(!color(i,1)){puts("0"); return 0;}
        int now  = 1,t1 = 1,t2 = 1;
        for(int i = 1;i <= n; i++){
            if(v[i] == 1) printf("a "),s1[++t1] = s[i];
            else printf("c "),s2[++t2] = s[i];
            while(s1[t1] == now||s2[t2] == now){
                if(s1[t1]==now) printf("b "),t1--;
                else printf("d "),t2--;
                now++;
            } 
        }
        return 0;
    }

     

    G102的孤儿们都要好好的啊。
  • 相关阅读:
    Linux安装jdk
    VUE和Element:Vue和Element基础使用,综合案例学生列表实现
    jQuery-css(border)样式内容火狐无法获取而谷歌可以获取问题问题
    Ajax:原生js实现Ajax,jQuery的get/post方式实现Ajax,jQuery的通用方式实现Ajax;JSON转换;搜索联想;瀑布流分页,点击按钮分页
    常用正则表达式大全,如何写出高效率的正则表达式?
    JQuery:JQuery基本语法,JQuery选择器,JQuery DOM,综合案例 复选框,综合案例 随机图片
    操作系统的一些概念题(1)
    谓词逻辑与归结原理的一些概念题
    模拟退火 Simulated annealing
    遗传算法Genetic Algorithm
  • 原文地址:https://www.cnblogs.com/ve-2021/p/9676197.html
Copyright © 2011-2022 走看看