1.      双栈排序

(twostack.pas/c/cpp)

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】

twostack.in

twostack.out

4

1 3 2 4

a b a a b b a b

【输入输出样例2】

twostack.in

twostack.out

4

2 3 4 1

0

【输入输出样例3】

twostack.in

twostack.out

3

2 3 1

a c a b b d

【限制】

30%的数据满足:
n<=10

50%的数据满足:
n<=50

100%的数据满足:
n<=1000

【思路】

构造“不可能”边+二分图着色

点的分配转化为了二分图的着色。

(以下摘自洛谷OI【题解】)

考虑对于任意两个数q1[i]和q1[j]来说,它们不能压入同一个栈中的充要条件是什么(注意没有必要使它们同时存在于同一个栈中,只是压入了同一个 栈).实际上,这个条件p是:存在一个k,使得i<j<k且q1[k]<q1[i]<q1[j].

首先证明充分性,即如果满足条件p,那么这两个数一定不能压入同一个栈.这个结论很显然,使用反证法可证.
假设这两个数压入了同一个栈,那么在压入q1[k]的时候栈内情况如下:
…q1[i]…q1[j]…
因为q1[k]比q1[i]和q1[j]都小,所以很显然,当q1[k]没有被弹出的时候,另外两个数也都不能被弹出(否则q2中的数字顺序就不是1,2,3,…,n了).
而之后,无论其它的数字在什么时候被弹出,q1[j]总是会在q1[i]之前弹出.而q1[j]>q1[i],这显然是不正确的.

接下来证明必要性.也就是,如果两个数不可以压入同一个栈,那么它们一定满足条件p.这里我们来证明它的逆否命题,也就是"如果不满足条件p,那么这两个数一定可以压入同一个栈."
不满足条件p有两种情况:一种是对于任意i<j<k且q1[i]<q1[j],q1[k]>q1[i];另一种是对于任意i<j,q1[i]>q1[j].
第一种情况下,很显然,在q1[k]被压入栈的时候,q1[i]已经被弹出栈.那么,q1[k]不会对q1[j]产生任何影响(这里可能有点乱,因为看起 来,当q1[j]<q1[k]的时候,是会有影响的,但实际上,这还需要另一个数r,满足j<k<r且 q1[r]<q1[j]<q1[k],也就是证明充分性的时候所说的情况…而事实上我们现在并不考虑这个r,所以说q1[k]对q1[j]没
有影响).
第二种情况下,我们可以发现这其实就是一个降序序列,所以所有数字都可以压入同一个栈.
这样,原命题的逆否命题得证,所以原命题得证.

此时,条件p为q1[i]和q1[j]不能压入同一个栈的充要条件也得证.

这样,我们对所有的数对(i,j)满足1<=i<j<=n,检查是否存在i<j<k满足p1[k]<p1[i]& lt;p1[j].如果存在,那么在点i和点j之间连一条无向边,表示p1[i]和p1[j]不能压入同一个栈.此时想到了什么?那就是二分图~
二分图的两部分看作两个栈,因为二分图的同一部分内不会出现任何连边,也就相当于不能压入同一个栈的所有结点都分到了两个栈中.
此时我们只考虑检查是否有解,所以只要o(n)检查出这个图是不是二分图,就可以得知是否有解.

然后处理最小字典序问题。实际上对二分图染色后对应的操作显然编号小的优先使用a操作,可以使得字典序尽量小。

这里要提二分图的一个性质:二分图中不同的连通分量染色是互不影响的。所以为了满足最小字典序的问题,可以选取编号最小的未染色结点染成1并对它所在连通分量染色。染完之后,模拟输出序列就可以了。

【代码】

 #include<iostream>
#include<cstdlib>
#include<vector>
#include<stack>
using namespace std;
const int maxn = +; int S[maxn],C[maxn];
vector<int> G[maxn];
int n; void dfs(int u,int c){
C[u]=c;
for(int i=;i<G[u].size();i++){
int v=G[u][i];
if(C[v]==C[u]) {
cout<<; exit();
}
else if(!C[v]) dfs(v,-c);
}
}
int main() {
ios::sync_with_stdio(false); cin>>n;
for(int i=;i<=n;i++) cin>>S[i];
int _min[maxn]; _min[n+]=<<;
for(int i=n;i;i--) _min[i]=min(_min[i+],S[i]);
for(int i=;i<n;i++)
for(int j=i+;j<=n;j++) if(S[i]<S[j] && _min[j+]<S[i]) { //i<j<k && (S[k]<S[i]<S[j])
G[i].push_back(j); G[j].push_back(i);
} for(int i=;i<=n;i++) if(!C[i]) dfs(i,); int aim=;
stack<int> sta,stb;
for(int i=;i<=n;i++) {
if(C[i]==) {
sta.push(S[i]); cout<<"a ";
}
else {
stb.push(S[i]); cout<<"c ";
}
while(!sta.empty()&&sta.top()==aim || !stb.empty()&&stb.top()==aim) {
if(!sta.empty()&&sta.top()==aim){
sta.pop(); cout<<"b ";
}
else {
stb.pop(); cout<<"d ";
}
aim++;
}
}
return ;
}

NOIP2008 双栈队列的更多相关文章

  1. Luogu1155 NOIP2008 双栈排序 【二分图染色】【模拟】

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

  2. C++实现一个简单的双栈队列

    双栈队列的原理是用两个栈结构模拟一个队列, 一个栈A模拟队尾, 入队的元素全部压入此栈, 另一个栈B模拟队首, 出队时将栈A的元素弹入栈B, 将栈B的栈顶元素弹出 此结构类似汉诺塔, 非常经典, 这里 ...

  3. NOIP2008双栈排序[二分图染色|栈|DP]

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  4. noip2008 双栈排序

    题目描述 Description \(Tom\)最近在研究一个有趣的排序问题.如图所示,通过\(2\)个栈\(S_1\)和\(S_2\),\(Tom\)希望借助以下\(4\)种操作实现将输入序列升序排 ...

  5. Noip2008双栈排序

    [问题描述] 用两个栈使一个1...n的排列变得有序.一共有四个操作: A.stack1.push() 读入一个放入栈一 B.stack1.pop() 弹出栈一放入输出序列 C.stack2.push ...

  6. NOIP2008双栈排序(贪心)

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  7. [题解] [NOIP2008] 双栈排序——关系的冲突至图论解法

    Problem 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操 ...

  8. [NOIP2008]双栈排序 【二分图 + 模拟】

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  9. [luogu1155 NOIP2008] 双栈排序 (二分图染色)

    传送门 Description Input 第一行是一个整数 n . 第二行有 n 个用空格隔开的正整数,构成一个 1−n 的排列. Output 共一行,如果输入的排列不是"可双栈排序排列 ...

随机推荐

  1. Tiny6410 交叉编译helloworld程序

    在工作目录下建立helloworld.c文件 #include <stdio.h> main() { printf("helloworld!\n"); } 保存关闭后. ...

  2. 时序列数据库武斗大会之什么是 TSDB ?

    本文选自 OneAPM Cloud Insight 高级工程师刘斌博客 . 刘斌,一个才思敏捷的程序员,<第一本 Docker 书>.<GitHub 入门与实践>等书籍译者,D ...

  3. Windows平台上C++开发内存泄漏检查方法

    充分的利用调试工具可以非常方便地避免内存泄漏问题. 这里介绍两种方法,互为补充,第一种是VC编译器提供的方法,第二种是专用的内存泄漏检查工具Memmory Validator.这两种方法的基本原理是一 ...

  4. Ubuntu环境下手动配置Hadoop1.2.1

    /×××××××××××××××××××××××××××××××××××××××××/ Author:xxx0624 HomePage:http://www.cnblogs.com/xxx0624/ ...

  5. POJ 2778 DNA sequence

    QAQ 做完禁忌 又做过文本生成器 这道题就是个水题啦 首先转移方程还是文本生成器的转移方程 但是注意到L很大,但是节点数很小 转移都是固定的,所以我们可以用AC自动机来构造转移矩阵 之后进行矩阵乘法 ...

  6. windows8 64位 IIS8 PHP5.5 安装 Imagemagick 组件

    为什么这里一定要说 windows 系统是64位呢,因为如果是系统是64位,那么PHP5.5 一般都会选择64的, Imagemagick 组件也会选择64位的, 但是操蛋的是 64位的Imagema ...

  7. HandlerThread 类的学习(转载)

    HandlerThread继承于Thread,所以它本质就是个Thread.HandlerThread类用于方便的创建一个含有looper的线程类,looper用来创建handler类.我们一般不创建 ...

  8. MyBatis-Spring 执行SQL语句的流程

    1. 从SqlSessionDaoSupport开始 通常我们使用MyBatis会让自己的DAO继承SqlSessionDaoSupport,那么SqlSessionDaoSupport是如何运作的呢 ...

  9. node.js模块之Buffer模块

    http://nodejs.org/api/buffer.html Pure JavaScript is Unicode friendly but not nice to binary data. W ...

  10. 去除windows的Shift+Space 全角半角切换

    windows7下的输入法,有一个“全/半角切换”的快捷方式“Shift+Space”,我们可以通过以下方式查看到: “开始”->“控制面板”->“区域和语言”->“键盘和语言”-& ...