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

你可能感兴趣的:(2008)