解题报告——双栈排序

题目(转自洛谷

Tom最近在研究一个有趣的排序问题。如图所示,通过2个栈S1和S2 ,Tom希望借助以下4种操作实现将输入序列升序排序

操作a
如果输入序列不为空,将第一个元素压入栈S1
操作b
如果栈S1空,将S1栈顶元素弹出至输出序列
操作c
如果输入序列不为空,将第一个元素压入栈S 2
操作d
如果栈S2不为空,将S2栈顶元素弹出至输出序列

如果一个1−n的排列P可以通过一系列操作使得输出序列为1,2,…,(n-1),n1,2,…,(n−1),n,Tom就称PP是一个“可双栈排序排列”。例如(1,3,2,4)(1,3,2,4)就是一个“可双栈排序序列”,而(2,3,4,1)(2,3,4,1)不是。下图描述了一个将(1,3,2,4)(1,3,2,4)排序的操作序列:<a,c,c,b,a,d,d,b><a,c,c,b,a,d,d,b>

当然,这样的操作序列有可能有几个,对于上例(1,3,2,4)(1,3,2,4),<a,c,c,b,a,d,d,b><a,c,c,b,a,d,d,b>是另外一个可行的操作序列。Tom希望知道其中字典序最小的操作序列是什么。

输入格式
第一行是一个整数n。

第二行有n个用空格隔开的正整数,构成一个1−n的排列。

输出格式
共一行,如果输入的排列不是“可双栈排序排列”,输出数字00;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。

输入输出样例
输入 #1
4
1 3 2 4
输出 #1
a b a a b b a b
输入 #2
4
2 3 4 1
输出 #2
0
输入 #3
3
2 3 1
输出 #3
a c a b b d
说明/提示
30%的数据满足: n≤10
50%的数据满足:n≤50
100%的数据满足:n≤1000

观察数据规模,发现这道题对时间复杂度的要求并不高,n2的算法可以轻松通过,甚至连logn n2也是可以的,再观察题干,发现这道题如果跳过模拟直接得出答案很困难,凭一己之力很难找到规律,所以最开始还是要从模拟当中找到答案。但是直接模拟也很难。让人有一种无从下手的感觉,那我们还是从特殊到一般试试。看见“双”,先想“单”,假设我们只有一个栈,怎么排序?在排序中,栈的作用到底是什么?仔细想一想,不难发现其实就是辅助交换逆序对,并且它的能力有限,对于2 3 1这样的数据是无能为力的。
那么“2 3 1”,这种数据有什么性质?它不单调!,对于没有单调性质的数据。我们会发现都不可以用单栈排序。
那么扩展到双栈呢?,这种情况下,我们就可以将1压进1号栈,2压进2号栈,3压进1号栈,再分别弹出3,1,2,就完成了排序。
那当其中有一个栈失去了单调性质,那么这个排序也就gg了。所以说,我们要判断可不可以用双栈排序,本质上就是要判断数列中存不存在a4<a1<a2<a3这一类的数据。当然我们可以暴力判O(4^n) , 也可以优化一下先预处理出后缀最小值,然后O(n^3 )判断,当然都会TLE。
那怎么办?两个栈交替存储输出,不就是一个二分图嘛?那利用二分图的思想,就能轻松在n2的时间复杂度内解决这道题了。
附上代码~
关于二分图的一些技巧就在注释里面了

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int Inf=0x3f3f3f3f;
int n,cnt=0,not_bip=0;//cnt记录操作数,目测cnt最后会等于2*n因为每个数都要进栈和出栈 
int len1=0,len2=0;//记录两个栈的大小 
int Wait_print=1;//我们当前该输出啥数 
int dt[1010][1010];//存图 
int Sm[1010];//后缀最小值 
int sl[1010];//原数列 
int Q[1000010];//Bfs队列 
int col[1010];//每个数的颜色 
int vis[1010];//Bfs visit数组 
int stack1[1010];//1栈 
int stack2[1010];//2栈 
char Oper[2020];//操作,这个数组可以不开,大家可以在过程中直接输出,而且会更快 
void Suffix_min()//预处理后缀最小值 
{
   
    Sm
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值