博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
双栈排序-NOIP2008T4
阅读量:4318 次
发布时间:2019-06-06

本文共 1312 字,大约阅读时间需要 4 分钟。


 题目描述:

  有两个栈A和B,以及四种操作:元素入栈A称为操作a,元素出栈A称为操作b,元素入栈B称为操作c,元素出栈B称为操作d。现在有一个长度为n(1≤N≤1000)的全排列序列,要求通过两个栈,输出1..N的序列,问能否达成,若能,则要求输出字典序最少的方案。

思考&分析:

    拿到这个题第一反应是:爆搜?时间复杂度(2^1000)^2=4^1000=1.148e+602……

  先把问题简化下,如果单栈怎么搞?

  你会发现单栈很好做:如果当前的要入栈的元素已经到了输出的时候,赶紧压进去然后输出来;否则你就先存在那儿,等它到了输出的时候看它是不是在栈顶,如果是把它输出来,否则就是不行。

  然后你会发现这个道理在双栈根本行不通。

  仍然考虑单栈,换个角度思考下,什么样的情况在单栈会挂掉?

  容易发现:当出现这样的序列时,单栈会挂掉:a[k]<a[i]<a[j]&&i<j<k。

  如果你有双栈,这样是不会挂的,你可以先把a[i]暂存在A栈,把a[j]暂存在B栈,然后问题就解决了。

  在双栈中,如果出现这样的序列,a[i]和a[j]必须存在不同的栈中,否则会挂掉。

  所以先要把这些i,j全部找出来,朴素找是O(N^3)的,会T,然而一个小小的后缀Min优化就可以是复杂度降为O(N^2)。

  找出来以后,你发现这是一个并查集裸题,开两倍数组,用i+n来表示i的对立面,对于必须存在不同栈中的i和j。

  i和j+n要合并到同一集合,j和i+n要合并到同一集合,但是如果你发现i和j或是i+n和j+n合并到同一集合去了,那么说明:出问题了。

  如果做完之后都没发现问题,那么你可以确定每个数要到A栈还是B栈(如果都可以去优先A栈)。

  依次模拟一下即可,按顺序入栈,发现能出栈就出栈。

  然后你就能A掉此题。

贴代码:

#include 
using namespace std;const int maxn=1005;int n,a[maxn],Min[maxn],f[maxn*2],bh[maxn*2];int t1,t2,st1[maxn],st2[maxn];int getfather(int x){ if (f[x]==x) return x; else f[x]=getfather(f[x]); return f[x];}int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); Min[n]=a[n]; for (int i=n-1;i>=1;i--) Min[i]=min(Min[i+1],a[i]); for (int i=1;i<=2*n;i++) f[i]=i; bool flag=true; int fa,fb,fc,fd; for (int i=1;i

转载于:https://www.cnblogs.com/chunlvxiong/p/7357690.html

你可能感兴趣的文章
牛客练习赛16 E求值
查看>>
matlab rank
查看>>
Asp.net系列--基础篇(三)
查看>>
css基础
查看>>
如何在tomcat中如何部署java EE项目
查看>>
【Python基础教程第2版】——第二讲:列表和元组
查看>>
小常识
查看>>
使用vscode开发python
查看>>
swift--调用系统单例实现打电话
查看>>
0038-算一算是一年中的第几天
查看>>
51nod 1094 【水题】
查看>>
003.第一个动画:绘制直线
查看>>
ng-深度学习-课程笔记-2: 神经网络中的逻辑回归(Week2)
查看>>
正则表达式的搜索和替换
查看>>
个人项目:WC
查看>>
地鼠的困境SSL1333 最大匹配
查看>>
flume+elasticsearch+kibana遇到的坑
查看>>
【MM系列】在SAP里查看数据的方法
查看>>
C#——winform
查看>>
CSS3 transform制作的漂亮的滚动式导航
查看>>