1. 程式人生 > >雙棧排序(codevs 1170)題解

雙棧排序(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.