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;
否則輸出字典序最小的操作序列,每兩個操作之間用空格隔開,行尾沒有空格。

數據范圍

30%的數據滿足: n<=10
50%的數據滿足: n<=50
100%的數據滿足: n<=1000

------------------------------------------------------------------------

 正解=圖匹配Orz。。

先考慮單棧排序

 顯然這是個由下到上的遞減棧。

 能單棧排序的情況: 不存在 (i<j<k 且  v[k]<v[i]<v[j])時即可進行排序

 必要性 :

     當 j 要進棧時,i 必須出棧,但 k 又必須在 i 前出棧,顯然不可以- =

 充分性:

     當 i<j<k 時除上述情況還有

        A : 當 v[i]>v[j] 時

             i ,j可以同時在棧中,無論v[k]的值如何,都能進行排序(顯然)

        B: 當 v[i]<v[j]<v[k ]時

             也顯然可以排序- =

        C:當 v[i]<v[k]<v[j]時

             好像也顯然可以排序- =

     所以顯然除 (i<j<k 且  v[k]<v[i]<v[j])都可進行排序 - =

  其實也可以像ak大神(Orz)一樣,拿1 2 3舉例證明,雖不怎么全面,但很好理解。

考慮完單棧回到雙棧排序

   就像歸並一樣,兩個都能排序,那合起來也能排序。

   如果存在(i<j<k 且  v[k]<v[i]<v[j]))時i , j ,就不能在同一棧里。

   預處理i ,j (i<j)如果存在上述情況,那他們就必然不在同一個棧里,在i,j間連一條線

   做一遍染色即可,出現非法情況(同一點染上不同顏色)就無解。

   讓完后做一個簡單的字典序最小進棧出棧操作,記下當前要出棧的數,然后依題意搞之即可(令人蛋疼- =)。

 代碼如下:

 1 #include<cstring>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<string>
 5 #include<iostream>
 6 #include<queue>
 7 #include<stack>
 8 #define INF 99999999
 9 #define LL long long
10 using namespace std;
11 int col[1001],next[10010],last[10010],s[10010],T,n,v[1001],K[1001],ans[3000];
12 stack<int> q[3];
13 void addedge(int x,int y){
14     next[++T]=last[x]; last[x]=T; s[T]=y;
15     next[++T]=last[y]; last[y]=T; s[T]=x; 
16 }
17 void DFS(int now,int c){
18     if(!col[now]) col[now]=c; 
19     else if(col[now]!=c){
20         printf("0");
21         exit(0);
22     } else return ;
23     for(int i=last[now];i;i=next[i]) DFS(s[i],3-c);
24 }
25 int main(){
26     scanf("%d",&n);
27     for(int i=1;i<=n;i++) scanf("%d",&v[i]);
28     K[n]=v[n];
29     for(int i=n-1;i;i--) K[i]=min(K[i+1],v[i]);
30     for(int i=1;i<=n;i++)
31      for(int j=i+1;j<n;j++)
32       if(K[j+1]<v[i]&&v[j]>v[i])
33        addedge(i,j);
34     for(int i=1;i<=n;i++) if(!col[i]) DFS(i,1);
35     int now=1;
36     int T=1;
37     while(1){
38         if(now>n) break;
39         if(col[T]==1&&(q[1].empty()||q[1].top()>v[T])){
40             q[1].push(v[T]);
41             ++T;
42             printf("a ");
43             continue ;
44         }
45         if(!q[1].empty()&&q[1].top()==now) {
46             printf("b "); 
47             q[1].pop();
48             ++now;
49             continue ;
50         }
51         if(col[T]==2&&(q[2].empty()||q[2].top()>v[T])){
52             q[2].push(v[T]);
53             ++T;
54             printf("c ");
55             continue ;
56         }
57         if(!q[2].empty()&&q[2].top()==now) {
58             printf("d "); 
59             q[2].pop();
60             ++now;
61             continue ;
62         }
63     }
64 }
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM