1. 程式人生 > >noip 2008 雙棧排序

noip 2008 雙棧排序

AI 用兩個 main () 入棧 top 現在 數字 AC

題目大意: 給定n和一串數字,這串數字是一個1~n的排列。現在要用兩個棧給這些數字排序。首先先判斷是否有解,有解的話再輸出字典序最小的方案:

入棧1,輸出a,出棧1,輸出b

入棧2,輸出c,出棧2,輸出d

分析:

首先必然要先考慮是否有解。對於沒有解的情況,必然是當到了某一個數x0時,棧1,棧2隊首元素都不能彈出,並且x0要比棧1、2的隊首元素都要大,這時就不能排序了。

所以考慮什麽時候A、B不能在同一個棧中的情況:

當且僅當,A<B,並且存在C,使得A>C.並滿足A位置在B前面,B位置在C前面。就是說,由於C的存在,A不能pop掉,但是B放進去,A就永遠pop不了了。

這樣就可以找到所有不能和x0在同一個棧裏的所有位置上的數了。

判斷無解時,將所有上述的A和B之間連一條無向邊,用二分圖染色或者帶偏移量的並查集都可以。

輸出時,因為要字典序最小,所以第一個元素必然要放進棧1,這樣可以預處理出來所有數要進入哪一個棧。能進棧1的都進棧1.

然後模擬實現,每次先要判斷是否可以pop掉棧頂元素,然後按照之前的預處理的方案放進數就可以了。

#include<bits/stdc++.h>
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 node{ int to,nxt; }bian[2*N]; void add(int x,int y) { bian[++cnt].nxt=head[x]; bian[cnt].to=y; head[x]=cnt; }//建邊 void dfs1(int x,int fa,int se)//1 black 2 white { if(flag) return; co[x]=se; for(int i=head[x];i;i=bian[i].nxt) {
int y=bian[i].to; if(y==fa) continue; if(co[y]) { if(co[y]==co[x]) { flag=1;return; } } else{ dfs1(y,x,3-se); } } }//二分圖染色判斷 void dfs2(int x,int se) { go[x]=se; for(int i=head[x];i;i=bian[i].nxt) { int y=bian[i].to; if(!go[y]) { dfs2(y,3-se); } } }//預處理該去的棧(其實也可以在二分圖染色時處理出來,就省了這步) void check(int now) { bool f=0; while(top[now]&&has+1==sta[now][top[now]]) { f=1; printf("%c ",now==1?b:d); has++; top[now]--; } if(f)//成功pop才找另一個 check(3-now); } //檢查能否pop int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) for(int j=n;j>=i+1;j--) { if(a[i]>a[j]) {la[i]=j;break;} }//找到A的最後面一個C的位置。 for(int i=1;i<=n;i++) for(int j=i+1;j<=la[i];j++) { if(a[i]<a[j]) { add(i,j); add(j,i); } }//A到C之間所有的B都要和A建邊 for(int i=1;i<=n;i++) { if(flag==1) break; if(!co[i]) dfs1(i,0,1); } if(flag) { printf("0"); return 0; }//判斷 go[1]=1; for(int x=1;x<=n;x++) { if(!go[x]) go[x]=1,dfs2(x,1); } for(int i=1;i<=n;i++) { check(1); check(2); sta[go[i]][++top[go[i]]]=a[i]; printf("%c ",go[i]==1?a:c); } check(1); check(2);//最後也要判斷,輸出完。 return 0; }

noip 2008 雙棧排序