[NOIP2008]双栈排序 【二分图 + 模拟】
题目描述
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
题解
#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]双栈排序 【二分图 + 模拟】的更多相关文章
- NOIP2008双栈排序[二分图染色|栈|DP]
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- [luogu1155 NOIP2008] 双栈排序 (二分图染色)
传送门 Description Input 第一行是一个整数 n . 第二行有 n 个用空格隔开的正整数,构成一个 1−n 的排列. Output 共一行,如果输入的排列不是"可双栈排序排列 ...
- [NOIp2008] 双栈排序 (二分图染色 + 贪心)
题意 给你一个长为 \(n\) 的序列 \(p\) ,问是否能够通过对于两个栈进行 push, pop(print) 操作使得最后输出序列单调递增(即为 \(1 \cdots n\) ),如果无解输出 ...
- Luogu1155 NOIP2008 双栈排序 【二分图染色】【模拟】
Luogu1155 NOIP2008 双栈排序 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过 2个栈 S1 和 S2 ,Tom希望借助以下 44 种操作实现将输入序列升序排序. 操作 ...
- $[NOIp2008]$双栈排序 栈/二分图/贪心
\(Sol\) 先考虑单栈排序,怎么样的序列可以单栈排序呢?设\(a_i\)表示位置\(i\)是哪个数.\(\exist i<j<k\),都没有\(a_k<a_i<a_j\), ...
- Noip2008双栈排序
[问题描述] 用两个栈使一个1...n的排列变得有序.一共有四个操作: A.stack1.push() 读入一个放入栈一 B.stack1.pop() 弹出栈一放入输出序列 C.stack2.push ...
- [题解] [NOIP2008] 双栈排序——关系的冲突至图论解法
Problem 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操 ...
- noip2008 双栈排序
题目描述 Description \(Tom\)最近在研究一个有趣的排序问题.如图所示,通过\(2\)个栈\(S_1\)和\(S_2\),\(Tom\)希望借助以下\(4\)种操作实现将输入序列升序排 ...
- NOIP2008双栈排序(贪心)
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
随机推荐
- Android开发笔记——视频录制播放常见问题
本文分享自己在视频录制播放过程中遇到的一些问题,主要包括: 视频录制流程 视频预览及SurfaceHolder 视频清晰度及文件大小 视频文件旋转 一.视频录制流程 以微信为例,其录制触发为按下(住) ...
- python基础数据类型补充
python_day_7 一. 今日主要内容: 1. 补充基础数据类型的相关知识点 str. join() 把列表变成字符串 列表不能再循环的时候删除. 因为索引会跟着改变 字典也不能直接循环删除.把 ...
- Jenkins Tomcat安装设置
Jenkins Tomcat安装设置 以下为必须满足Jenkins Tomcat设置的先决条件. 第1步:验证安装Java 要验证Java安装,打开控制台并执行以下Java命令. OS 任务 命令 W ...
- and_or_not 逻辑运算符的操作注解!
python操作:
- WEB前端开发流程总结
作者声明:本博客中所写的文章,都是博主自学过程的笔记,参考了很多的学习资料,学习资料和笔记会注明出处,所有的内容都以交流学习为主.有不正确的地方,欢迎批评指正 WEB前端开发项目流程总结 1.新建项目 ...
- php作用域限定符
双冒号::被认为是作用域限定操作符,用来指定类中不同的作用域级别.::左边表示的是作用域,右边表示的是访问的成员. 系统定义了两个作用域,self和parent.self表示当前类的作用域,在类之外的 ...
- Java中的静态变量static
package com.wangcf; public class Test { String name="你好"; static String sex="男"; ...
- 02_Java基础_第2天(变量、运算符)_讲义
今日内容介绍 1.变量 2.运算符 01变量概述 * A: 什么是变量? * a: 变量是一个内存中的小盒子(小容器),容器是什么?生活中也有很多容器, * 例如水杯是容器,用来装载水:你家里的大衣柜 ...
- ansible介绍和安装
ansible是由 Python 编写的强大的配置管理解决方案,ansible 的特点就在于它的简洁与高效率 ansible与其他的配置管理工具不同点在于:不需要你在想要配置的每个节点上安装自己的组件 ...
- oracle & 的用法!
/*select * from emp_bak where deptno = &"Department number" order by ename; select * f ...