noip2008 双栈排序
描述
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希望知道其中字典序最小的操作序列是什么。
格式
输入格式
第一行是一个整数n。
第二行有n个用空格隔开的正整数,构成一个1~n的排列。
输出格式
输出文件共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;
否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
数据范围
30%的数据满足: n<=10
50%的数据满足: n<=50
100%的数据满足: n<=1000
------------------------------------------------------------------------
正解=图匹配Orz。。
先考虑单栈排序
显然这是个由下到上的递减栈。
能单栈排序的情况: 不存在 (i<j<k 且 v[k]<v[i]<v[j])时即可进行排序
必要性 :
当 j 要进栈时,i 必须出栈,但 k 又必须在 i 前出栈,显然不可以- =
充分性:
当 i<j<k 时除上述情况还有
A : 当 v[i]>v[j] 时
i ,j可以同时在栈中,无论v[k]的值如何,都能进行排序(显然)
B: 当 v[i]<v[j]<v[k ]时
也显然可以排序- =
C:当 v[i]<v[k]<v[j]时
好像也显然可以排序- =
所以显然除 (i<j<k 且 v[k]<v[i]<v[j])都可进行排序 - =
其实也可以像ak大神(Orz)一样,拿1 2 3举例证明,虽不怎么全面,但很好理解。
考虑完单栈回到双栈排序
就像归并一样,两个都能排序,那合起来也能排序。
如果存在(i<j<k 且 v[k]<v[i]<v[j]))时i , j ,就不能在同一栈里。
预处理i ,j (i<j)如果存在上述情况,那他们就必然不在同一个栈里,在i,j间连一条线
做一遍染色即可,出现非法情况(同一点染上不同颜色)就无解。
让完后做一个简单的字典序最小进栈出栈操作,记下当前要出栈的数,然后依题意搞之即可(令人蛋疼- =)。
代码如下:
1 #include<cstring> 2 #include<algorithm> 3 #include<cstdio> 4 #include<string> 5 #include<iostream> 6 #include<queue> 7 #include<stack> 8 #define INF 99999999 9 #define LL long long 10 using namespace std; 11 int col[1001],next[10010],last[10010],s[10010],T,n,v[1001],K[1001],ans[3000]; 12 stack<int> q[3]; 13 void addedge(int x,int y){ 14 next[++T]=last[x]; last[x]=T; s[T]=y; 15 next[++T]=last[y]; last[y]=T; s[T]=x; 16 } 17 void DFS(int now,int c){ 18 if(!col[now]) col[now]=c; 19 else if(col[now]!=c){ 20 printf("0"); 21 exit(0); 22 } else return ; 23 for(int i=last[now];i;i=next[i]) DFS(s[i],3-c); 24 } 25 int main(){ 26 scanf("%d",&n); 27 for(int i=1;i<=n;i++) scanf("%d",&v[i]); 28 K[n]=v[n]; 29 for(int i=n-1;i;i--) K[i]=min(K[i+1],v[i]); 30 for(int i=1;i<=n;i++) 31 for(int j=i+1;j<n;j++) 32 if(K[j+1]<v[i]&&v[j]>v[i]) 33 addedge(i,j); 34 for(int i=1;i<=n;i++) if(!col[i]) DFS(i,1); 35 int now=1; 36 int T=1; 37 while(1){ 38 if(now>n) break; 39 if(col[T]==1&&(q[1].empty()||q[1].top()>v[T])){ 40 q[1].push(v[T]); 41 ++T; 42 printf("a "); 43 continue ; 44 } 45 if(!q[1].empty()&&q[1].top()==now) { 46 printf("b "); 47 q[1].pop(); 48 ++now; 49 continue ; 50 } 51 if(col[T]==2&&(q[2].empty()||q[2].top()>v[T])){ 52 q[2].push(v[T]); 53 ++T; 54 printf("c "); 55 continue ; 56 } 57 if(!q[2].empty()&&q[2].top()==now) { 58 printf("d "); 59 q[2].pop(); 60 ++now; 61 continue ; 62 } 63 } 64 }