双栈排序 2008年NOIP全国联赛提高组(二分图染色)
双栈排序
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 & Hint
30%的数据满足: 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; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。