• 双栈排序 2008年NOIP全国联赛提高组(二分图染色)


    双栈排序

     

    2008年NOIP全国联赛提高组

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 大师 Master
     
     
    题目描述 Description

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

    输入描述 Input Description

    输入的第一行是一个整数n。

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

    输出描述 Output Description

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

    样例输入 Sample Input

    【样例1】

    4

    1 3 2 4

     

    【样例2】

    4

    2 3 4 1

     

    【样例3】

    3

    2 3 1

    样例输出 Sample Output

    【样例1】

    a b a a b b a b

    【样例2】

    0

    【样例3】

    a c a b b d

    数据范围及提示 Data Size & Hint

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

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

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

    /*
    若不能双栈排序,一定存在冲突
    把冲突连边,因为只有两个栈,判断可否二分图染色即可
    考虑冲突。若有i<j<k a[k]<a[i]<a[j] 则一定不能单栈排序 
    若i<j<k<x 有a[x]<a[i]<a[j]<a[k]则一定不能双栈排序
    预处理后缀最小值,把冲突连边即可。 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<queue>
    #include<stack>
    
    #define N 1007
    #define inf 0x3f3f3f3f
    #define B 1
    
    using namespace std;
    int n,ans,cnt;
    int a[N],f[N],col[N],head[N];
    stack<int>s1,s2;
    struct edge{
        int u,v,net;
    }e[N<<1];
    
    inline void add(int u,int v)
    {
        e[++cnt].v=v;e[cnt].net=head[u];head[u]=cnt;
    }
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f; 
    }
    
    void bfs(int u)
    {
        queue<int>q;q.push(u);col[u]=B;
        while(!q.empty())
        {
            int now=q.front();q.pop();
            for(int i=head[now];i;i=e[i].net)
            {
                int v=e[i].v;
                if(col[v]==-1) col[v]=col[now]^1,q.push(v);
                else if(col[v]!=(col[now]^1)){printf("0
    ");exit(0);}
            }
        }
    }
    
    int main()
    {
        memset(col,-1,sizeof col);
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        f[n+1]=inf;
        for(int i=n;i>=1;i--) f[i]=min(f[i+1],a[i]);
        for(int i=1;i<=n;i++)
          for(int j=i+1;j<=n;j++)
            if(a[i]>f[j+1] && a[i]<a[j]) add(i,j),add(j,i);
            
        for(int i=1;i<=n;i++) 
          if(col[i]==-1) bfs(i);
        cnt=1;
        for(int i=1;i<=n;i++)
        {
            if(col[i]==B) s1.push(a[i]),printf("a ");
            else s2.push(a[i]),printf("c ");
            while((!s1.empty() && s1.top()==cnt) || (!s2.empty() && s2.top()==cnt))
            {
                if(!s1.empty() && s1.top()==cnt) s1.pop(),printf("b ");
                else s2.pop(),printf("d ");
                ++cnt;
            }
        }
        return 0;
    }
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    erlang遍历目录
    C/C++ makefile自动生成工具(comake2,autotools,linux),希望能为开源做点微薄的贡献!
    shell 文件操作
    互联网分享知识(一)
    分页查询,你真的懂吗?
    awk神器
    Unicode编码解码在线转换工具
    awk 留底
    软件开发真的这么简单吗?
    php性能优化
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7723656.html
Copyright © 2020-2023  润新知