zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    (打包报错)AS打包报错:Generate Signed APK: Errors while building APK. You can find the errors in the 'Messages' view.
    NABCD
    石家庄地铁站项目最终总结报告
    团队冲刺2.7
    团队冲刺2.6
    团队冲刺2.5
    团队冲刺2.4
    团队冲刺2.3
    用户体验评价——win10自带微软拼音输入法
    团队冲刺2.2
  • 原文地址:https://www.cnblogs.com/Blacko/p/3373313.html
Copyright © 2011-2022 走看看