noip 2008 雙棧排序

2021-10-24 09:45:32 字數 1790 閱讀 4754

題目大意: 給定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 如果輸入序列不為空,...