Vijos1605 NOIP2008 提高组T4 双栈排序 BFS
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - Vijos1605
题意概括
有1个1~n的排列,有2个栈,现在通过以下操作,使得出栈序列有序。
操作a 当前元素入栈<S1>
操作b 弹出S1栈顶元素
操作c 当前元素入栈<S2>
操作d 弹出S2栈顶元素
如果无法使得出栈序列有序,那么输出0.
否则输出满足条件的字典序最小的操作序列。
题解
首先我们可以证明,任意时刻,任意一个栈中的元素,一定满足自底向上呈降序。
如果不呈降序呢?
那么会出现大的先出栈,小的后出栈的情况,所以一定不行。
我们考虑2个元素a[i],a[j],(i<j)。
可以得到信息:
如果a[i]<a[j]那么a[i]先出栈
否则 a[j]先出栈
然后好像没有其他信息了。
问题很严峻。
于是我们考虑3个元素a[i],a[j],a[k](i<j<k)
考虑所有情况。
如果a[i]<a[j]<a[k],那么a[i],a[j]可能在同一个栈中。
同样,
如果a[i]<a[k]<a[j],那么a[i],a[j]可能在同一个栈中。
如果a[j]<a[i]<a[k],那么a[i],a[j]可能在同一个栈中。
如果a[j]<a[k]<a[i],那么a[i],a[j]可能在同一个栈中。
如果a[k]<a[j]<a[i],那么a[i],a[j]可能在同一个栈中。(这5中情况都可以有具体操作次序,注意是“可能”)
但是,
如果a[k]<a[i]<a[j],那么a[i],a[j]一定不可能在同一个栈中。
为什么?
首先a[i]进栈。
因为a[k]<a[i],所以在a[k]出栈之前,a[i]不能出栈。
然而因为a[i]<a[j],如果a[i]与a[j]放在同一个栈中,那么会出现题解第一句中表述的不合法情况。
因此a[i],a[j]一定不会在同一个栈中。
于是我们可以先确定i,j,然后大力枚举k,按照不在同一个栈中的关系建立无向图。相邻的节点一定不会在同一个栈中。这个操作的复杂度为n^3。
而实际上,我们可以先预处理一个后缀最小值,那么大力枚举k的时间复杂度就被压缩掉了。
优化之后,这个操作的复杂度为n^2。
建图之后,就是匹配栈。
黑白染色即可。(假设栈1为白色(0),栈2为黑色(1))
又由于题目要字典序最小的,所以我们尽量给编号小的节点染成白色就可以了。
于是我们大力跑一遍广搜。
当然染色的过程中会出现相邻节点颜色相同的情况,那么就是无解,直接输出0。
广搜完了之后,每一个数字安排的栈位置都已经弄好了。
然后就是模拟了。
模拟的时候,还是要注意字典序最小的问题。
注意按照之前匹配的一定有解的。
模拟具体过程:
我们弄一个计数器cnt,表示当前出栈到了哪一个数字。
对于每次压入元素前,如果栈1的栈顶元素是cnt+1,那么要先将栈1出栈。
因为,如果当前元素匹配的是栈2,那么自然就是栈1出栈优先。
如果是栈1,那么元素值一定会比cnt+1要大,不满足最前面的那一条。
然后,注意对于同一个栈,入栈的优先级一定比出栈高。
所以,我们尽量提前入栈。
但是入栈是有条件的,要维持序列降序。
那么就要先出栈,直到满足降序为止。
出栈也是有规矩的。要满足cnt+1,所以是两个栈乱序出栈的。
我的程序貌似有点小问题,但是数据水,过去了……
具体:
如果匹配栈2,那么出栈操作之后,满足栈2降序之后,其实有字典序更小的方案。
因为栈2入栈,是c,而栈1出栈是b,所以栈1先出栈是赚的。但是我忘记判这个情况了。
然后居然……
至此,rzO膜拜大佬出据人Orz
代码
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <queue>
using namespace std;
const int N=1000+5,Inf=100000;
struct Stack{
int v[N],t;
void clear(){
t=0;
}
void push(int x){
v[++t]=x;
}
void pop(){
t--;
}
bool empty(){
return t==0;
}
int top(){
if (t==0)
return Inf;
return v[t];
}
}s1,s2;
int n,a[N],Min[N],match[N],vis[N],cnt;
bool g[N][N];
queue <int> q;
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
Min[n]=10000;
for (int i=n-1;i>=1;i--)
Min[i]=min(Min[i+1],a[i+1]);
memset(g,0,sizeof g);
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
if (a[i]<a[j]&&Min[j]<a[i])
g[i][j]=g[j][i]=1;
memset(vis,0,sizeof vis);
for (int i=1;i<=n;i++){
if (vis[i])
continue;
while (!q.empty())
q.pop();
vis[i]=1,match[i]=0;
q.push(i);
while (!q.empty()){
int x=q.front();
q.pop();
for (int j=1;j<=n;j++){
if (!g[x][j])
continue;
if (!vis[j]){
match[j]=match[x]^1;
q.push(j);
vis[j]=1;
}
else if (match[j]==match[x]){
printf("0");
fclose(stdin);fclose(stdout);
return 0;
}
}
}
}
cnt=0;
s1.clear(),s2.clear();
for (int i=1;i<=n;i++){
while (s1.top()==cnt+1){
printf("b ");
s1.pop();
cnt++;
}
if (match[i]==0){
while (a[i]>s1.top()&&(s1.top()==cnt+1||s2.top()==cnt+1))
if (s1.top()==cnt+1){
printf("b ");
s1.pop();
cnt++;
}
else {
printf("d ");
s2.pop();
cnt++;
}
s1.push(a[i]);
printf("a ");
}
if (match[i]==1){
while (a[i]>s2.top()&&(s1.top()==cnt+1||s2.top()==cnt+1))
if (s1.top()==cnt+1){
printf("b ");
s1.pop();
cnt++;
}
else {
printf("d ");
s2.pop();
cnt++;
}
s2.push(a[i]);
printf("c ");
}
}
while (!s1.empty()||!s2.empty())
if (s1.top()<s2.top()){
printf("b ");
s1.pop();
}
else {
printf("d ");
s2.pop();
}
return 0;
}
Vijos1605 NOIP2008 提高组T4 双栈排序 BFS的更多相关文章
- BZOJ 2080: [Poi2010]Railway 双栈排序
2080: [Poi2010]Railway Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 140 Solved: 35[Submit][Statu ...
- [NOIP2008] 提高组 洛谷P1155 双栈排序
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- 【提高组NOIP2008】双栈排序 (twostack.pas/c/cpp)
[题目描述] Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈 ...
- 双栈排序 2008年NOIP全国联赛提高组(二分图染色)
双栈排序 2008年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description Tom最近在研究一个有 ...
- Luogu1155 NOIP2008 双栈排序 【二分图染色】【模拟】
Luogu1155 NOIP2008 双栈排序 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过 2个栈 S1 和 S2 ,Tom希望借助以下 44 种操作实现将输入序列升序排序. 操作 ...
- NOIP2008双栈排序[二分图染色|栈|DP]
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- noip2008 双栈排序
题目描述 Description \(Tom\)最近在研究一个有趣的排序问题.如图所示,通过\(2\)个栈\(S_1\)和\(S_2\),\(Tom\)希望借助以下\(4\)种操作实现将输入序列升序排 ...
- #include <NOIP2008 Junior> 双栈排序 ——using namespace wxl;
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- 【NOIP2008】双栈排序
感觉看了题解还是挺简单的,不知道当年chty同学为什么被卡了呢么久--所以说我还是看题解了 原题: Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将 ...
随机推荐
- 20155334 2016-2017-2 《Java程序设计》第五周学习总结
20155334 2016-2017-2 <Java程序设计>第五周学习总结 教材学习内容总结 第八章:异常处理 Java中所有错误都会被打包为对象,在编程的时候会遇到因各种原因而导致的错 ...
- SQL Server 2008“备份集中的数据库备份与现有的数据库不同”解决方法
对于SQL Server 2008,有几个地方是要注意的,比方在还原数据库时,不像2000里边将数据库和文件区分的很细, 统一均为文件,这就使还原的数据库文件制定为. bak.那么想还原2000的数据 ...
- Java EE之Hibernate异常总结【5】java.lang.StackOverflowError[栈溢出]
Exception in thread "main" java.lang.StackOverflowError at java.lang.reflect.InvocationTar ...
- [HAOI2018]奇怪的背包 (DP,数论)
[HAOI2018]奇怪的背包 \(solution:\) 首先,这一道题目的描述很像完全背包,但它所说的背包总重量是在模P意义下的,所以肯定会用到数论.我们先分析一下,每一个物品可以放无数次,可以达 ...
- 【Python】【辅助程序】练手小程序:记录外网动态IP地址
练手小程序 程序作用:对IP实时记录: 1.定时获取外网IP,存储在本地文件中: 编写思路: 1)收集获取外网的API接口 http://bbs.125.la/thread-1383897 ...
- Linux之V4L2基础编程【转】
转自:https://www.cnblogs.com/emouse/archive/2013/03/04/2943243.html 本文内容来源于网络,本博客进行整理. 1. 定义 V4L2(Vide ...
- ioremap 与 mmap【转】
转自:http://blog.csdn.net/junllee/article/details/7415732 内存映射 对于提供了MMU(存储管理器,辅助操作系统进行内存管理,提供虚实地址转换等硬件 ...
- CSS高度塌陷问题解决方案
高度塌陷的存在:原因分析 1 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /& ...
- 超级wifi
超级wifi (super wi-fi)是相对于现有的wifi提出的改进版,执行响应的 802.11af标准. 802.11af 标准是2014年2月提出的,它的主要特点是"建议在电视频率之 ...
- 源码编译安装nginx1.4.7
传统上基于进程或线程模型架构的web服务通过每进程或每线程处理并发连接请求,这势必会在网络和I/O操作时产生阻塞,其另一个必然结果则是对内存或CPU的利用率低下.生成一个新的进程/线程需要事先备好其运 ...