• 双栈排序(codevs 1170)题解


    【问题描述】

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

    【样例输入1】

        4

        1 3 2 4

    【样例输出1】 

         a b a a b b a b

    【样例输入2】

        4

        2 3 4 1

    【样例输出2】

        0

    【样例输入3】

        3

        2 3 1

    【样例输出3】

        a c a b b d

    【解题思路】

        本题为NOIP2008提高组第四题,初看觉得这应该是有史以来最水的提高组最后一题了,这不是模拟吗?只不过模拟的东西多了一点而已,然而,当我写着写着,就发现模拟的有点不对劲了……

        好吧,这道题的正解应该是图的染色+模拟……

        是的,没错,你没有看错,第四题居然要模拟!!!

        染色其实是一个深搜的过程,染色是为了区分程序从头到尾始终不能放在一个栈中的数,然后为了保证是字典序最小,因此尽量往栈1中放,如果有始终无法放到同一个栈中的数被放到了同一个栈(这里的被放到同一个栈是指的染成同一种颜色),那么就无解,输出0。(染色的方法可以百度floodfill或者种子染色法)

        那么问题来了……挖掘机哪家……不对……怎么区分始终不能放在一个栈中的数呢?

        如果存在k使得i<j<k且ak<ai<aj则ai和aj不能进入同一个栈。

        我们可以手推一下,如果k>j>i说明,j在i的后面进栈,k在j的后面进栈,而此时ai<aj,那么如果ai和aj进了同一个栈,那么就会是aj先出栈,就肯定不是从小到大排好序的了。

        染完色后就好办了,直接模拟进栈出栈的过程……如果是最小值,就出,否则就进,然后因为已经染了色了,根据染的色判断它是进(出)栈1还是栈2,然后输出相应的字符即可。

        现在还有一个最最担心的问题,怎么确定这个数是不是当前需要出栈的数(即最小值)?好吧……其实是我眼睛瞎了,是的,我为此纠结了半天,然后看题目……一个1~n的排列P……直接最小值赋值为1,然后出栈了就Inc……

    【代码实现】

     1 uses math;
     2 var flag:array[1..1000,1..1000] of boolean;
     3     q1,q2,color,a,f:array[1..1001] of longint;
     4     n,i,j,sum,t1,t2:longint;
     5 procedure dfs(x,c:longint);
     6 var i:longint;
     7 begin
     8  color[x]:=c;
     9  for i:=1 to n do
    10   if flag[x,i] then
    11    begin
    12     if color[i]=c then
    13      begin
    14       writeln(0);
    15       halt;
    16      end;
    17     if color[i]=0 then
    18      dfs(i,3-c);
    19    end;
    20 end;
    21 begin
    22  readln(n);
    23  for i:=1 to n do
    24   read(a[i]);
    25  f[n+1]:=maxlongint;
    26  for i:=n downto 1 do
    27   f[i]:=min(a[i],f[i+1]);
    28  for i:=1 to n-1 do
    29   for j:=i+1 to n do
    30    if (a[i]<a[j])and(f[j+1]<a[i]) then
    31     begin
    32      flag[i,j]:=true;
    33      flag[j,i]:=true;
    34     end;//初始化,哪些是始终无法进同一个栈的
    35  for i:=1 to n do
    36   if color[i]=0 then
    37    dfs(i,1);//给每一个数染色
    38  sum:=1;
    39  for i:=1 to n do
    40   begin
    41    if color[i]=1 then
    42     begin
    43      inc(t1);
    44      q1[t1]:=a[i];
    45      write('a ');
    46     end
    47    else
    48     begin
    49      inc(t2);
    50      q2[t2]:=a[i];
    51      write('c ');
    52     end;
    53    while ((t1<>0)and(q1[t1]=sum))or((t2<>0)and(q2[t2]=sum)) do
    54     begin
    55      if (0<>t1)and(q1[t1]=sum) then
    56       begin
    57        dec(t1);
    58        write('b ');
    59       end
    60      else
    61       begin
    62        dec(t2);
    63        write('d ');
    64       end;
    65      inc(sum);//最小值
    66     end;
    67   end;//最恶心的模拟……
    68 end.
  • 相关阅读:
    如何自定义长连接策略
    知物由学 | 这些企业大佬如何看待2018年的安全形势?
    网易云易盾朱星星:最容易被驳回的10大APP过检项
    网易云易盾朱浩齐:视听行业步入强监管和智能时代
    知物由学 | 人工智能、机器学习和深度学习如何在网络安全领域中应用?
    知物由学 | 广告欺诈:如何应对数字广告里分羹者?
    知物由学 | 如何应对日益强大的零日攻击
    不再任人欺负!手游安全的进阶之路
    邪恶的三位一体:机器学习、黑暗网络和网络犯罪
    PAT 1053. Path of Equal Weight
  • 原文地址:https://www.cnblogs.com/PengBoLiuXu/p/4522400.html
Copyright © 2020-2023  润新知