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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双栈排序 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\n");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;
}

 

以上是关于双栈排序 2008年NOIP全国联赛提高组(二分图染色)的主要内容,如果未能解决你的问题,请参考以下文章

聪明的质监员 2011年NOIP全国联赛提高组(二分+前缀和)

笨小猴 2008年NOIP全国联赛提高组

cogs luogu 传纸条 2008年NOIP全国联赛提高组 WD

旅行家的预算 1999年NOIP全国联赛普及组NOIP全国联赛提高组

1058 合唱队形 2004年NOIP全国联赛提高组

1068 乌龟棋 2010年NOIP全国联赛提高组