題目大意: 給定n和一串數字,這串數字是乙個1~n的排列。現在要用兩個棧給這些數字排序。首先先判斷是否有解,有解的話再輸出字典序最小的方案:
入棧1,輸出a,出棧1,輸出b
入棧2,輸出c,出棧2,輸出d
分析:首先必然要先考慮是否有解。對於沒有解的情況,必然是當到了某乙個數x0時,棧1,棧2隊首元素都不能彈出,並且x0要比棧1、2的隊首元素都要大,這時就不能排序了。
所以考慮什麼時候a、b不能在同乙個棧中的情況:
當且僅當,ac.並滿足a位置在b前面,b位置在c前面。就是說,由於c的存在,a不能pop掉,但是b放進去,a就永遠pop不了了。
這樣就可以找到所有不能和x0在同乙個棧裡的所有位置上的數了。
判斷無解時,將所有上述的a和b之間連一條無向邊,用二分圖染色或者帶偏移量的並查集都可以。
輸出時,因為要字典序最小,所以第乙個元素必然要放進棧1,這樣可以預處理出來所有數要進入哪乙個棧。能進棧1的都進棧1.
然後模擬實現,每次先要判斷是否可以pop掉棧頂元素,然後按照之前的預處理的方案放進數就可以了。
#include
using
namespace std;
const
int n=
1010
;int a[n]
,la[n]
,co[n]
;int n;
int head[n]
;int cnt=1;
bool flag=0;
int sta[3]
[n];
//記錄棧1、棧2
int top[3]
;//記錄棧頂
int go[n]
;//這個位置上的數要去哪乙個棧
int has;
//已經出棧到幾號
struct nodebian[
2*n]
;void
add(
int x,
int y)
//建邊
void
dfs1
(int x,
int fa,
int se)
//1 black 2 white
}else}}
//二分圖染色判斷
void
dfs2
(int x,
int se)}}
//預處理該去的棧(其實也可以在二分圖染色時處理出來,就省了這步)
void
check
(int now)
if(f)
//成功pop才找另乙個
check(3
-now);}
//檢查能否pop
intmain()
}//找到a的最後面乙個c的位置。
for(
int i=
1;i<=n;i++
)for
(int j=i+
1;j<=la[i]
;j++)}
//a到c之間所有的b都要和a建邊
for(
int i=
1;i<=n;i++)if
(flag)
//判斷
go[1]
=1;for
(int x=
1;x<=n;x++
)for
(int i=
1;i<=n;i++
)check(1
);check(2
);//最後也要判斷,輸出完。
return0;
}
NOIP2008 雙棧排序
link 考慮什麼時候 i,j i,j i,j 可以被放到同乙個棧裡面 我們只需要考慮如果我們把 i,j i,j i,j 放一起後面會不會出現矛盾 假設有 i j i j k,觀察每一種排列,只有當 a k a kak 的時候,是會出現問題的,我們不能構造一種方案滿足這個條件 所以我們通過計算字尾最...
noip 2008 雙棧排序
題目大意 給定n和一串數字,這串數字是乙個1 n的排列。現在要用兩個棧給這些數字排序。首先先判斷是否有解,有解的話再輸出字典序最小的方案 入棧1,輸出a,出棧1,輸出b 入棧2,輸出c,出棧2,輸出d 分析 首先必然要先考慮是否有解。對於沒有解的情況,必然是當到了某乙個數x0時,棧1,棧2隊首元素都...
noip2008 雙棧排序
tom 最近在研究乙個有趣的排序問題。如圖所示,通過 2 個棧 s 1 和 s 2 tom 希望借助以下 4 種操作實現將輸入序列公升序排序。操作 a 如果輸入序列不為空,將第乙個元素壓入棧 s 1 操作 b 如果棧 s 1 不為空,將 s 1 棧頂元素彈出至輸出序列 操作 c 如果輸入序列不為空,...