1. 程式人生 > >雙棧排序 2008年NOIP全國聯賽提高組(二分圖染色)

雙棧排序 2008年NOIP全國聯賽提高組(二分圖染色)

push space style efault panel none ive hint slide

雙棧排序

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全國聯賽提高組(二分圖染色)