Noip2008雙棧排序

2022-06-01 10:18:07 字數 3002 閱讀 8937

【問題描述】

用兩個棧使乙個1...n的排列變得有序。

一共有四個操作:

a.stack1.push()   讀入乙個放入棧一

b.stack1.pop()   彈出棧一放入輸出序列

c.stack2.push()  讀入乙個放入棧二

d.stack2.pop()  彈出棧二放入輸出序列

給你乙個初始的排列,

求乙個字典序最小的操作序列使得變得有序,若沒有滿足條件的操作序列,輸出'0'。

sample.in                                sample.out

4     1 3 2 4                               a b a a b b a b

4     2 3 4 1                               0

3     2 3 1                                  a c a b b d

【分析】

嗯嗯嗯...這題好有意思啊...然後開始埋頭苦幹,發現好神奇啊!

1.棧原來真的可以排序誒!

2.雙棧原來也可以排序誒!

3.原來第二個樣例真的不能排序誒!

....於是沉默了....於是開始糾結....什麼樣的資料不能用雙棧排序呢?

........

思考了很久很久.....似乎想不出來什麼東西....

不過我在構造中發現....每當乙個棧要掛的時候,往往可以禍水東引,將即將堵住的元素放到另乙個棧中去,每次兩個棧都堵住的時候...恩恩,雙棧排序就掛了!

於是開始想另乙個問題:什麼樣的資料不能用單棧排序....

隨便造了乙個:2 3 1 恩,就掛了。

因為2應該在3前出去,但是因為1在後面,所以2出不去,就被3堵住了....

所以只要有 i

【題外】【嚴謹證明】【copy from codevs】【不想看的記住這個結論就好了】

考慮對於任意兩個數a[i]和a[j]來說,它們不能壓入同乙個棧中的充要條件是什麼(注意沒有必要使它們同時存在於同乙個棧中,只是壓入了同乙個棧).

實際上,這個條件p是:存在乙個k,使得i

首先證明充分性,即如果滿足條件p,那麼這兩個數一定不能壓入同乙個棧.這個結論很顯然,使用反證法可證.

假設這兩個數壓入了同乙個棧,那麼在壓入a[k]的時候棧內情況如下: 

…a[i]…a[j]… 

因為a[k]比a[i]和a[j]都小,所以很顯然,當a[k]沒有被彈出的時候,另外兩個數也都不能被彈出(否則輸出序列中的數字順序就不是1,2,3,…,n了).

而之後,無論其它的數字在什麼時候被彈出,a[j]總是會在a[i]之前彈出.而a[j]>a[i],這顯然是不正確的.

接下來證明必要性.也就是:如果兩個數不可以壓入同乙個棧,那麼它們一定滿足條件p.

這裡我們來證明它的逆否命題,也就是"如果不滿足條件p,那麼這兩個數一定可以壓入同乙個棧."

不滿足條件p有兩種情況: 1. 對於任意ia[i]; 2. 對於任意ia[j].

第一種情況下,很顯然,在a[k]被壓入棧的時候,a[i]已經被彈出棧.那麼,a[k]不會對a[j]產生任何影響(這裡可能有點亂,因為看起來,當a[j]

所以如果遇到這樣的 i,j,它們一定不能丟到乙個棧裡面去,於是給它們並查集連個虛點?或者連條什麼邊[二分圖染色]。

唔...下面就好辦啦....[我打的二分圖染色,就講這個哈]

二分圖染色 [只有兩種顏色1,0] 就是在每乙個連通塊上,對乙個點染上黑色[belong[x]=1],然後對所有連的邊染上和它不同的顏色[belong[v]=1^belong[x]],當然還得給每個元素下乙個是否已經找到顏色的標記sure,以免多次染色和漏掉矛盾。[矛盾的情況很好辦咯...就是發現兩個已經確定的,而且練了邊的點染成了同乙個顏色!....然後就槍斃了...]

因為要求操作序列的字典序最小,所以我們希望前面的元素能盡可能放進棧一中,假設棧一中的都是顏色為黑的,那麼只需要按照順序對每乙個不曾染過色的點染成黑色,然後拓展它所在的連通塊即可。

最後,我們都知道了所有點在哪個棧中....就可以開始開心的模擬了!

記錄乙個cot表示現在希望彈出的元素是幾,發現可以彈出cot的時候一直彈彈彈[ 彈走魚尾紋 ] 就可以了,具體還不懂就看**咯.....[有貼心小注釋]

1 #include2 #include3

4using

namespace

std;

56 inline int

in()

1213

const

int maxn=1010;14

15struct nodenode[maxn*maxn];

1819

#define now node[point].data

20#define then node[point].next

2122

int n,cnt,t1,t2,cot=1;23

inta[maxn],head[maxn],belong[maxn];

24int

f[maxn],s1[maxn],s2[maxn];

25bool

sure[maxn],over;

2627 inline int min(int a,int

b)30

31 inline void add(int u,int v)

3536

void dfs(int

x)42}43

else

//如果相鄰的點未曾染色

44 belong[now]=1-belong[x],dfs(now); //

染色,並擴充套件所在連通分塊 45}

4647 inline void pop()54}

5556

intmain()73}

7475

for(int i=1;i<=n;i++)

82return0;

83 }

view code

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隊首元素都...

noip 2008 雙棧排序

題目大意 給定n和一串數字,這串數字是乙個1 n的排列。現在要用兩個棧給這些數字排序。首先先判斷是否有解,有解的話再輸出字典序最小的方案 入棧1,輸出a,出棧1,輸出b 入棧2,輸出c,出棧2,輸出d 分析 首先必然要先考慮是否有解。對於沒有解的情況,必然是當到了某乙個數x0時,棧1,棧2隊首元素都...