1812. 【提高組NOIP2008】雙棧排序 (twostack.pas/c/cpp)
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)排序的操作序列:
當然,這樣的操作序列有可能有幾個,對於上例(1,3,2,4),是另外一個可行的操作序列。Tom希望知道其中字典序最小的操作序列是什麼。
輸入
輸入文件twostack.in的第一行是一個整數n。
第二行有n個用空格隔開的正整數,構成一個1~n的排列。
輸出
輸出文件twostack.out共一行,如果輸入的排列不是“可雙棧排序排列”,輸出數字0;否則輸出字典序最小的操作序列,每兩個操作之間用空格隔開,行尾沒有空格。
樣例輸入
【輸入輸出樣例1】
4
1 3 2 4
【輸入輸出樣例2】
4
2 3 4 1
【輸入輸出樣例3】
3
2 3 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
一道蠻坑的題目。。。。。
比賽思路:亂打。(三個樣例沒過)
期望得分:
(最高):100
(最低):0
結果出來,
9.1分。呵呵噠…….
轉入正題
正解:玄學之二分圖染色
具體操作
(1)連邊。如果a[k] < a[i] < a[j]且i< j< k,將i與j連邊;
(連邊的意思是不可以在同一個棧裏)
方法:記錄一下b[i,j](i後有沒有a[j]),o(2n^2)解決;
(2)入棧:先記錄c[i](代表a[i]的狀態,0自由,1在1棧,2在2棧)如果c[i]=0,c[i]入1棧並將於c[i]連邊的點入2棧。
Warning:給出一組數據:
(if c[i]=0 then)
10
10 2 8 1 7 9 3 4 5 6
2-8,8-9,7-9連邊
i=1時,10入1棧;
i=2時,2入1棧,8入2棧;
i=3時,8已經在2棧,7入1棧,2不用入1棧(已入);
i=4時,1入1棧;
i=5時,7入1棧(?),9入2棧!
但,8與9不能進一個棧!
難道輸出0?
不對,7可以入2棧,那麼9入1棧,成立。
這種”被迫“入2棧的例子,要判斷。
設要入棧的點爲i,i的連邊點有j。
if c[j]=1 then i入2棧。
如果i入2棧都不行,輸出0.
if c[i]=1 then 將i的所有連邊點j,c[j]=2;
if c[i]=2 then 將i的所有連邊點j,c[j]=1;
(3)出棧。
t=0;
inc(t);if c[t]=0 then break;(if c[t]=1 then s:=s+’b ’ ;if c[t]=2 then s:=s+’d ‘;)
就這樣,直到t>=n,退出程序。
做完了。
注意:
1:連雙向邊;
2:細節!
3:那些字符要用s儲存,不要直接輸出。
4:字典序時,可能a操作比d先,要判斷。(否則90.9)
代碼:
請勿抄襲:(6293 bytes)
var
f:array[1..100000,1..2] of longint;
x,y:array[0..10000] of longint;
a,q:array[1..10000] of longint;
b:array[1..1000,1..1000] of longint;
c,d:array[1..100000] of longint;
i,j,k,m,n,o,p,l,s1,t,min:longint;
bz:boolean;
zu:array[1..1000,1..1000] of boolean;
g:array[0..10000] of boolean;
s:ansistring;
procedure insert(x,y:longint);
begin
inc(t);
f[t,1]:=y;
f[t,2]:=q[x];
q[x]:=t;
end;
begin
assign(input,'twostack.in');reset(input);
assign(output,'twostack.out');rewrite(output);
readln(n);
for i:=1 to n do read(a[i]);
for i:=1 to n do begin
min:=maxlongint;
for j:=i+1 to n do
if a[j]<min then begin
min:=a[j];
end;
if min=maxlongint then continue;
for j:=min+1 to n do b[i,j]:=1;
for j:=1 to min do b[i,j]:=0;
end;
fillchar(zu,sizeof(zu),true);
fillchar(g,sizeof(g),true);
for i:=1 to n do begin
for j:=i+1 to n do begin
if a[i]<a[j] then begin
if b[j,a[i]]=1 then begin
insert(a[i],a[j]);
writeln(a[i],' ',a[j]);
zu[a[i],a[j]]:=false;zu[a[j],a[i]]:=false;
end;
end;
end;
end;
s1:=1; t:=0;
for i:=1 to n do begin
if g[i]=false then continue;
if c[a[i]]=0 then begin
d[a[i]]:=x[0];
k:=q[a[i]];
bz:=true;
while k<>0 do begin
if c[f[k,1]]=1 then begin
bz:=false;
end;
if bz=false then break;
k:=f[k,2];
end;
k:=q[a[i]];
if bz=true then begin
s:=s+'a ';
inc(x[0]);
x[x[0]]:=a[i];c[a[i]]:=1;
while k<>0 do begin
if c[f[k,1]]=0 then begin
inc(y[0]);
y[y[0]]:=f[k,1];
c[f[k,1]]:=2;
d[a[i]]:=y[0];
end;
k:=f[k,2];
end;
end else begin
s:=s+'c ';
inc(y[0]);
y[y[0]]:=a[i];c[a[i]]:=2;
while k<>0 do begin
if c[f[k,1]]=0 then begin
inc(x[0]);
x[x[0]]:=f[k,1];
c[f[k,1]]:=1;
end;
k:=f[k,2];
end;
end;
end else if c[a[i]]=1 then begin
s:=s+'a ';
k:=q[a[i]];
while k<>0 do begin
if c[f[k,1]]=1 then begin
writeln(0);
close(input);close(output);
halt;
end;
if c[f[k,1]]=0 then begin
inc(y[0]);
y[y[0]]:=f[k,1];
c[f[k,1]]:=2;
//s:=s+'c ';
end;
k:=f[k,2];
end;
end else begin
k:=q[a[i]];
s:=s+'c ';
while k<>0 do begin
if c[f[k,1]]=2 then begin
writeln(0);
close(input);close(output);
halt;
end;
if c[f[k,1]]=0 then begin
inc(x[0]);
x[x[0]]:=f[k,1];
c[f[k,1]]:=1;
//s:=s+'a ';
end;
k:=f[k,2];
end;
end;
t:=s1;
j:=s1;
repeat
if j=0 then continue;
if c[j]<>0 then begin
if c[j]=1 then begin
s:=s+'b ';
inc(j);
dec(x[0]);
end
else begin
if x[0]=0 then begin
s:=s+'a ';
inc(x[0]);x[x[0]]:=a[i+1];c[i+1]:=1; g[i+1]:=false;
s:=s+'d ';
end else s:=s+'d ';
inc(j);
end;
end;
if c[j]=0 then begin
t:=j;
break;
end;
until j>n;
s1:=t;
//writeln(s);
end;
writeln(s);
close(input);close(output);
end.