[NOIP2008] 提高组 洛谷P1155 双栈排序
题目描述
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希望知道其中字典序最小的操作序列是什么。
输入输出格式
输入格式:
输入文件twostack.in的第一行是一个整数n。
第二行有n个用空格隔开的正整数,构成一个1~n的排列。
输出格式:
输出文件twostack.out共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
输入输出样例
【输入样例1】 4 1 3 2 4 【输入样例2】 4 2 3 4 1 【输入样例3】 3 2 3 1
【输出样例1】 a b a a b b a b 【输出样例2】 0 【输出样例3】 a c a b b d
说明
30%的数据满足: n<=10
50%的数据满足: n<=50
100%的数据满足: n<=1000
考虑单栈排序:如果有三个元素a[i]<a[j] && a[i]>a[k],且它们的顺序 i<j<k,a[i]出栈以后a[j]才能进栈,a[k]出栈以后a[i]才能出栈,显然无法满足要求。
所以,如果三个数满足以上条件,它们是不能同进一个栈的。
先n downto 1倒推出每个数后面最小的数,作为a[k],然后枚举a[i],a[j],若符合上述条件,则在i,j之间连边,表示它们不能进同一个栈。
之后进行二分图染色,如果遇到颜色矛盾,说明不能把冲突的点对分成两组,也就是问题无解。
如果没有冲突,则问题有解,模拟即可。
1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<stack> 8 using namespace std; 9 const int mxn=12000; 10 struct edge{ 11 int v; 12 int nxt; 13 }e[mxn]; 14 int hd[mxn],mct=0; 15 void add_edge(int u,int v){ 16 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct; 17 return; 18 } 19 int a[mxn],n; 20 int mini[mxn]; 21 int c[mxn]; 22 int ans[mxn],t=0; 23 bool dfs(int u){ 24 if(c[u]==-1)c[u]=0; 25 for(int i=hd[u];i;i=e[i].nxt){ 26 int v=e[i].v; 27 if(c[v]==-1){ 28 c[v]=c[u]^1; 29 if(!dfs(v))return 0; 30 } 31 else{ 32 if(c[v]==c[u])return 0; 33 } 34 } 35 return 1; 36 } 37 stack<int>tp1,tp2; 38 int main(){ 39 memset(c,-1,sizeof c); 40 int i,j; 41 scanf("%d",&n); 42 mini[n+1]=0x3f3f3f; 43 for(i=1;i<=n;i++)scanf("%d",&a[i]); 44 for(i=n;i;i--) mini[i]=min(mini[i+1],a[i]); 45 for(i=1;i<n;i++) 46 for(j=i+1;j<=n;j++){ 47 if(a[i]<a[j] && a[i]>mini[j+1]){ 48 add_edge(j,i); 49 add_edge(i,j); 50 } 51 } 52 for(i=1;i<=n;i++) 53 if(c[i]==-1){ 54 if(!dfs(i)){ 55 printf("0\n"); 56 return 0; 57 } 58 } 59 int now=1; 60 i=1; 61 while(1){ 62 if(now>n)break; 63 if(c[i]==0 && (tp1.empty() || tp1.top()>a[i])){ 64 tp1.push(a[i]); 65 ans[++t]=1; 66 i++; 67 continue; 68 } 69 if(!tp1.empty() && tp1.top()==now){ 70 ans[++t]=2; 71 tp1.pop(); 72 now++; 73 continue; 74 } 75 if(c[i]==1 && (tp2.empty() || tp2.top()>a[i])){ 76 tp2.push(a[i]); 77 ans[++t]=3; 78 i++; 79 continue; 80 } 81 if(!tp2.empty() && tp2.top()==now){ 82 tp2.pop(); 83 ans[++t]=4; 84 now++; 85 continue; 86 } 87 } 88 for(i=1;i<=t;i++)printf("%c ",(char)ans[i]+'a'-1); 89 printf("\n"); 90 return 0; 91 }