题目描述

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:

【输入样例1】
4
1 3 2 4
【输入样例2】
4
2 3 4 1
【输入样例3】
3
2 3 1
输出样例#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

题解

本蒟蒻刚开始就陷入了贪心的思维,结果30分。。WA

为什么会这样呢?按照贪心的思维,对于当前元素,优先考虑扔进s1,扔不进再考虑弹出s1,弹不出再考虑扔进s2,再考虑弹出s2,还弹不出就无解

看起来很完美= =,实际上暗藏漏洞——这个算法会将一些可行的情况判为无解
因为当你将一个元素扔进s1时,当前是最优了,但这个元素会对之后的元素产生影响,这个是没有考虑进去的,所以这个时候有可能扔进s2才可能有解



具体怎么做呢?
想想,对于扔进同一个栈的两个数A[i] < A[j] 且 i < j,,在j扔进去之前,i一定已经弹出来了,这个时候如果j后面如果还存在这比A[i]小的数,说明A[i]此时不应弹出来,这就形成矛盾了,所以这样的情况i与j不能同时存在于一个栈中
即对于所有i < j && A[i] < A[j],若存在k > j && A[k] < A[i],则i和j不在同一栈中

由这个关系我们可以利用二分图求解:
对于所有不能存在与同一栈的元素之间连边,对二分图进行一次二分染色【优先染1号色,即入s1栈】,如果染色成功,则有解,且每个数改进哪一个栈也已经确定

最后就是模拟,题目说这是一个1~n的排列= =【一开始没看到弄了好久】,所以我们记录下当前应该弹出哪一个数,
对于进s1的数,能进则进,不能进就弹
对于进s2的数,进之前先看看s1能不能弹【即s1栈顶是不是当前该弹出的数】,再进行s2的操作:能进则进,否则就弹

最后就解出来啦~~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#define LL long long int
using namespace std;
const int maxn = 1005,maxm = 100005,INF = 2000000000; inline int read(){
int out = 0,flag = 1;char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1;c = getchar();}
while (c >= 48 &&c <= 57) {out = out * 10 + c - 48;c = getchar();}
return out * flag;
} int N,A[maxn],Min[maxn],color[maxn]; struct node{
int v,id;
}e[maxn]; inline bool operator < (const node& a,const node& b){
return a.v < b.v;
} int head[maxn],nedge = 0;
struct EDGE{
int to,next;
}edge[maxm]; inline void build(int u,int v){
edge[nedge] = (EDGE) {v,head[u]};
head[u] = nedge++;
edge[nedge] = (EDGE) {u,head[v]};
head[v] = nedge++;
} void init(){
fill(head,head + maxn,-1);
N = read();
for (int i = 1; i <= N; i++){
e[i].v = A[i] = read();
e[i].id = i;
}
Min[N + 1] = INF;
for (int i = N; i > 0; i--) Min[i] = min(A[i],Min[i + 1]);
} bool flag = true; void dfs(int u,int c){
color[u] = c;
int to;
for (int k = head[u]; k != -1; k = edge[k].next)
if (!color[to = edge[k].to]){
dfs(to,((c - 1) ^ 1) + 1);
if (!flag) return;
}else if (color[to] == color[u]){
flag = false;
return;
}
} void Build(){
for (int i = 1; i <= N; i++)
for (int j = i + 1; j <= N; j++)
if (A[i] < A[j] && A[i] > Min[j + 1])
build(i,j);
for (int i = 1; i <= N; i++){
if (!color[i]){
dfs(i,1);
if (!flag) return;
}
}
} const char *alpha = "abcd";
int ans[2 * maxn],ansi = 0;
stack<int> s[2]; void solve(){
int cnt = 1;
for (int i = 1; i <= N; i++){
if (color[i] == 1){
s[0].push(A[i]);
ans[++ansi] = 0;
}else {
s[1].push(A[i]);
ans[++ansi] = 2;
}
while (!s[0].empty() && s[0].top() == cnt){
s[0].pop();
ans[++ansi] = 1;
cnt++;
}
while (!s[1].empty() && s[1].top() == cnt){
s[1].pop();
ans[++ansi] = 3;
cnt++;
}
}
while (!s[0].empty() || !s[1].empty()){
if (!s[0].empty() && s[0].top() == cnt){
s[0].pop();
ans[++ansi] = 1;
cnt++;
}
if (!s[1].empty() && s[1].top() == cnt){
s[1].pop();
ans[++ansi] = 3;
cnt++;
}
}
} int main(){
init();
Build();
if (!flag) cout<<0<<endl;
else {
/*for (int i = 1; i <= N; i++) printf("%d ",color[i]);
cout<<endl;*/
solve();
printf("%c",alpha[ans[1]]);
for (int i = 2; i <= ansi; i++)
printf(" %c",alpha[ans[i]]);
printf("\n");
}
return 0;
}

[NOIP2008]双栈排序 【二分图 + 模拟】的更多相关文章

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

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

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

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

  3. [NOIp2008] 双栈排序 (二分图染色 + 贪心)

    题意 给你一个长为 \(n\) 的序列 \(p\) ,问是否能够通过对于两个栈进行 push, pop(print) 操作使得最后输出序列单调递增(即为 \(1 \cdots n\) ),如果无解输出 ...

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

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

  5. $[NOIp2008]$双栈排序 栈/二分图/贪心

    \(Sol\) 先考虑单栈排序,怎么样的序列可以单栈排序呢?设\(a_i\)表示位置\(i\)是哪个数.\(\exist i<j<k\),都没有\(a_k<a_i<a_j\), ...

  6. Noip2008双栈排序

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

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

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

  8. noip2008 双栈排序

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

  9. NOIP2008双栈排序(贪心)

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

随机推荐

  1. python-模块详解

    模块: 模块的分类: 第三方模块/扩展模块:没在安装python解释器的时候安装的那些功能 自定义模块:你写的功能如果是一个通用的功能,那你就把它当做一个模块 内置模块:安装python解释器的时候跟 ...

  2. info信息的获取

    一.绝对路径(_SERVER[“SCRIPT_FILENAME”])这个是最常用,也是最有效的一个办法,找到phpinfo()页面可以直接找到网站的绝对路径,对于写shell和信息搜集是必不可少的.二 ...

  3. 用Micro:bit做床头灯

    这是一个非常简单的项目,给孩子们介绍感应和控制,使用光敏电阻LDR作为光线传感器和床头灯的LED. 这也介绍了模拟输入的概念.数字输入为ON或OFF.只有0和1两种可能的条件.仿真输入是一系列可能值中 ...

  4. 小白初识 - 归并排序(MergeSort)

    归并排序是一种典型的用分治的思想解决问题的排序方式. 它的原理就是:将一个数组从中间分成两半,对分开的两半再分成两半,直到最终分到最小的单位(即单个元素)的时候, 将已经分开的数据两两合并,并且在合并 ...

  5. 用gdb调试程序(Linux环境)

    一般来说,GDB主要帮忙你完成下面四个方面的功能: 1.启动你的程序,可以按照你的自定义的要求随心所欲的运行程序.    2.可让被调试的程序在你所指定的调置的断点处停住.(断点可以是条件表达式)   ...

  6. Java如何调用shell脚本的

    有些时候会碰到这样的场景:java的功能里面要嵌入一个功能点,这个功能是通过是shell脚本实现的.这种时候就需要Java对脚本调用的支持了. 测试环境 Ubuntu16.04 i3-6100,12G ...

  7. PHP性能优化 -理论篇

    什么情况下,遇到了PHP性能问题?    1 PHP语法使用的不恰当    2 使用PHP语言做不了它不擅长做的事    3 用php语言连接的服务不给力    4 PHP自身的短板    5 我也不 ...

  8. tikv 安装

    export HostIP="127.0.0.1" docker run -d -p 2379:2379 -p 2380:2380 --name pd pingcap/pd \ - ...

  9. Scrum立会报告+燃尽图(十月二十三日总第十四次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2246 项目地址:https://git.coding.net/zhang ...

  10. Alpha版发布 - 感谢有你们

    在本次alpha开发的过程中,很感谢组长王航对我信任,让我统筹大家的工作任务和进度,使我对项目管理有了深刻的理解. 我也要感谢邹双黛,因为我以前很少做文字类的工作,写东西非常生硬,邹双黛即使在有做家教 ...