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

    https://www.luogu.org/problem/show?pid=1155

    题目描述

    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希望知道其中字典序最小的操作序列是什么。

    输入输出格式

    输入格式:

    输入文件twostack.in的第一行是一个整数n。

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

    输出格式:

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

    输入输出样例

    输入样例#1:
    【输入样例1】
    4
    1 3 2 4
    【输入样例2】
    4
    2 3 4 1
    【输入样例3】
    3
    2 3 1
    
    
    输出样例#1:
    【输出样例1】
    a b a a b b a b
    【输出样例2】
    0
    【输出样例3】
    a c a b b d

    说明

    30%的数据满足: n<=10

    50%的数据满足: n<=50

    100%的数据满足: n<=1000

    如果两个数a[i]、a[j]不能放到同一个栈里,那么存在i<j<k,a[k]<a[i]<a[j]

    所以可以枚举i,j,k,将不能放在一起的a[i]、a[j]连边,看最后能否称为一个二分图

    枚举i,j,k ,O(n³),采用后缀优化

    f[i]表示i以后的数的最小值

    枚举i,j,判断a[i]<a[j]&&f[j]<a[i]

    #include<stack>
    #include<cstdio>
    #include<algorithm>
    #define N 1001
    using namespace std;
    int n,a[N],f[N];
    int front[N*N],nxt[N*N],to[N*N],tot;
    int col[N]; 
    stack<int>s1,s2;
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
    }
    bool dfs(int now,int c)
    {
        col[now]=c;
        for(int i=front[now];i;i=nxt[i])
        {
            if(col[to[i]] && col[to[i]]==col[now]) return false;
            else if(!col[to[i]] && !dfs(to[i],c^1)) return false; 
        }
        return true;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        f[n]=10001;
        for(int i=n-1;i;i--) f[i]=min(f[i+1],a[i+1]);
        for(int i=1;i<n;i++)
         for(int j=i+1;j<=n;j++)
          if(a[i]<a[j] && f[j]<a[i]) add(a[i],a[j]); 
        for(int i=1;i<=n;i++)
         if(!col[a[i]]) 
          if(!dfs(a[i],2)) { printf("0"); return 0; }
        int x=1;
        for(int i=1;i<=n;i++)
        {
            if(col[a[i]]==2) printf("a "),s1.push(a[i]);
            else printf("c "),s2.push(a[i]);
            while((!s1.empty()&&s1.top()==x) || (!s2.empty()&&s2.top()==x))
            {
                if(!s1.empty()&&s1.top()==x) { printf("b "); s1.pop(); }
                else { printf("d "); s2.pop(); }
                x++; 
            }
        }
    } 
  • 相关阅读:
    COM编程入门
    DirectShow Filter 开发典型例子分析 ——字幕叠加 (FilterTitleOverlay)1
    互联网的三大巨头 百度 阿里巴巴 腾讯(BAT)
    入侵Tomcat服务器一次实战
    TinyXML:一个优秀的C++ XML解析器
    Apache POI (JAVA处理Office文档的类库)
    MediaInfo源代码分析 4:Inform()函数
    MediaInfo源代码分析 3:Open()函数
    洛谷 P3905 道路重建
    CF16A Flag
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7275641.html
Copyright © 2011-2022 走看看