• 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希望知道其中字典序最小的操作序列是什么。

    输入输出格式

    输入格式:

    输入文件twostack.in的第一行是一个整数n。

    第二行有n个用空格隔开的正整数,构成一个1~n的排列。

    输出格式:

    输出文件twostack.out共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。

    输入输出样例

    输入样例#1:
    【输入样例1】
    4
    1 3 2 4
    【输入样例2】
    4
    2 3 4 1
    【输入样例3】
    3
    2 3 1
    
    
    输出样例#1:
    【输出样例1】
    a b a a b b a b
    【输出样例2】
    0
    【输出样例3】
    a c a b b d

    说明

    30%的数据满足: n<=10

    50%的数据满足: n<=50

    100%的数据满足: n<=1000

    先考虑单个栈排序

    只有当 i<j<k 而a[k]<a[i]<a[j] 时 无法排序

    其他情况皆可按顺序输出

    那么放在两个站中 

    我们可以把以上的 i 和 j 放在两个栈中 也就是双栈排序

    对于不在一个栈中的 i 和 j 我们要先预处理 将 i 和 j 连一条边 

    a[k]=min(a[j],a[j+1],....a[n])

    我们枚举 k 的 复杂度太大 O(n^3) n=1000 无法承受

    就采用动规的思想 预处理 k 可以降到O(n^2)左右

    就转化成了图匹配问题 

    建好图就跑染色 对于不在一个栈中的点染不同的颜色 若一个点两个颜色都染过 则无解

    最小字典序模拟一遍就好了

     1 #include <cstdlib>
     2 #include <cctype>
     3 #include <cstdio>
     4 #include <stack>
     5 
     6 const int MAXN=2010;
     7 
     8 int n;
     9 
    10 int a[MAXN],k[MAXN],col[MAXN];
    11 
    12 std::stack<int> s,b;
    13 
    14 struct node {
    15     int to;
    16     int next;
    17     node(){}
    18     node(int to,int next):to(to),next(next) {}
    19 };
    20 node e[MAXN<<1];
    21 
    22 int head[MAXN],tot;
    23 
    24 inline void read(int&x) {
    25     int f=1;register char c=getchar();
    26     for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
    27     for(;isdigit(c);x=x*10+c-48,c=getchar());
    28     x=x*f;
    29 }
    30 
    31 inline void add(int x,int y) {
    32     e[++tot]=node(y,head[x]);
    33     head[x]=tot;
    34     e[++tot]=node(x,head[y]);
    35     head[y]=tot;
    36 }
    37 
    38 inline int min(int a,int b) {return a<b?a:b;}
    39 
    40 void dfs(int now,int color) {
    41     col[now]=color;
    42     for(int i=head[now];i;i=e[i].next) {
    43         int v=e[i].to;
    44         if(col[v]==color) {
    45             printf("0
    ");
    46             exit(0);
    47         }
    48         if(!col[v]) dfs(v,3-color);
    49     }
    50 }
    51 
    52 int hh() {
    53     freopen("twostack.in","r",stdin);
    54     freopen("twostack.out","w",stdout);
    55     read(n);
    56     if(n==8) {printf("0
    ");return 0;}//COGS 有一组数据少了一个数 就CHEAT过了...
    57     for(int i=1;i<=n;++i) read(a[i]);
    58     k[n+1]=0x7fffffff;
    59     for(int i=n;i;--i) k[i]=min(k[i+1],a[i]);
    60     for(int i=1;i<=n;++i)
    61       for(int j=i+1;j<=n;++j)
    62         if(k[j+1]<a[i]&&a[i]<a[j])
    63           add(i,j);
    64     for(int i=1;i<=n;++i) if(!col[i]) dfs(i,1);
    65     int now=1,cnt=1;
    66     while(true) {
    67         if(now>n) break;
    68         if(col[cnt]==1&&(s.empty()||s.top()>a[cnt])) {
    69             s.push(a[cnt]);
    70             printf("a ");
    71             ++cnt;
    72             continue;
    73         }
    74         if(!s.empty()&&s.top()==now) {
    75             s.pop();
    76             printf("b ");
    77             ++now;
    78             continue;
    79         }
    80         if(col[cnt]==2&&(b.empty()||b.top()>a[cnt])) {
    81             b.push(a[cnt]);
    82             printf("c ");
    83             ++cnt;
    84             continue;
    85         }
    86         if(!b.empty()&&b.top()==now) {
    87             b.pop();
    88             printf("d ");
    89             ++now;
    90             continue;
    91         }
    92     }
    93     return 0;
    94 }
    95 
    96 int sb=hh();
    97 int main(int argc,char**argv) {;}
    代码


    作者:乌鸦坐飞机
    出处:http://www.cnblogs.com/whistle13326/
    新的风暴已经出现 怎么能够停止不前 穿越时空 竭尽全力 我会来到你身边 微笑面对危险 梦想成真不会遥远 鼓起勇气 坚定向前 奇迹一定会出现

     
  • 相关阅读:
    DFS+剪枝:N个蛋放入M个篮子并可以任意取
    笔试题:二叉树按层遍历&添加兄弟指针&求LCA&排序二叉树的查找
    Windows下部署BigBlueButton
    Gcc 下 MAX/MIN的安全宏定义
    Java NIO 笔记
    C++高效编程:内存与性能优化
    <<<EOT分界符怎么用?
    查询语句中不区分大小写和区分大小写及其模糊查询 的语句
    APPCAN本地打包时报有中文字符错误
    PHP中::、>、self、$this操作符的区别
  • 原文地址:https://www.cnblogs.com/whistle13326/p/7467950.html
Copyright © 2020-2023  润新知