雙棧排序 2008年NOIP全國聯賽提高組(二分圖染色)
阿新 • • 發佈:2017-10-24
push space style efault panel none ive hint slide
題目描述 Description
雙棧排序
2008年NOIP全國聯賽提高組
時間限制: 1 s 空間限制: 128000 KB 題目等級 : 大師 Master題目描述 Description
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)排序的操作序列:<a,c,c,b,a,d,d,b>
當然,這樣的操作序列有可能有幾個,對於上例(1,3,2,4),<a,c,c,b,a,d,d,b>是另外一個可行的操作序列。Tom希望知道其中字典序最小的操作序列是什麽。
輸入描述 Input Description輸入的第一行是一個整數n。
第二行有n個用空格隔開的正整數,構成一個1~n的排列。
輸出描述 Output Description輸出共一行,如果輸入的排列不是“可雙棧排序排列”,輸出數字0;否則輸出字典序最小的操作序列,每兩個操作之間用空格隔開,行尾沒有空格。
樣例輸入 Sample Input【樣例1】
4
1 3 2 4
【樣例2】
4
2 3 4 1
【樣例3】
3
2 3 1
樣例輸出 Sample Output【樣例1】
a b a a b b a b
【樣例2】
0
【樣例3】
a c a b b d
數據範圍及提示 Data Size & Hint30%的數據滿足: n<=10
50%的數據滿足: n<=50
100%的數據滿足: n<=1000
/* 若不能雙棧排序,一定存在沖突 把沖突連邊,因為只有兩個棧,判斷可否二分圖染色即可 考慮沖突。若有i<j<k a[k]<a[i]<a[j] 則一定不能單棧排序 若i<j<k<x 有a[x]<a[i]<a[j]<a[k]則一定不能雙棧排序 預處理後綴最小值,把沖突連邊即可。 */ #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<queue> #include<stack> #define N 1007 #define inf 0x3f3f3f3f #define B 1 using namespace std; int n,ans,cnt; int a[N],f[N],col[N],head[N]; stack<int>s1,s2; struct edge{ int u,v,net; }e[N<<1]; inline void add(int u,int v) { e[++cnt].v=v;e[cnt].net=head[u];head[u]=cnt; } inline int read() { int x=0,f=1;char c=getchar(); while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f; } void bfs(int u) { queue<int>q;q.push(u);col[u]=B; while(!q.empty()) { int now=q.front();q.pop(); for(int i=head[now];i;i=e[i].net) { int v=e[i].v; if(col[v]==-1) col[v]=col[now]^1,q.push(v); else if(col[v]!=(col[now]^1)){printf("0\n");exit(0);} } } } int main() { memset(col,-1,sizeof col); n=read(); for(int i=1;i<=n;i++) a[i]=read(); f[n+1]=inf; for(int i=n;i>=1;i--) f[i]=min(f[i+1],a[i]); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(a[i]>f[j+1] && a[i]<a[j]) add(i,j),add(j,i); for(int i=1;i<=n;i++) if(col[i]==-1) bfs(i); cnt=1; for(int i=1;i<=n;i++) { if(col[i]==B) s1.push(a[i]),printf("a "); else s2.push(a[i]),printf("c "); while((!s1.empty() && s1.top()==cnt) || (!s2.empty() && s2.top()==cnt)) { if(!s1.empty() && s1.top()==cnt) s1.pop(),printf("b "); else s2.pop(),printf("d "); ++cnt; } } return 0; }
雙棧排序 2008年NOIP全國聯賽提高組(二分圖染色)