题意

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

每个操作有个优先级,push(1) > pop(1) > push(2) > pop(2) ,输出优先级最大的一组解。

\(n \le 1000\)

题解

有兴趣可以来逛逛 我的博客。

洛谷前面大部分题解,对于后面直接模拟的思路肯定是错的,本文介绍一个基于贪心的算法(不知道对不对,因为没有强数据验证)。

首先考虑只有一个栈的时候如何解决这个问题。

就是对于一对位置 \((i, j)\) 是否能共存三个位置 \(i < j < k\) 存在 \(p_k < p_i < p_j\) 是不可行的,因为 \(p_k\) 需要在 \(p_i\) 与 \(p_j\) 之前出栈,但 \(p_i\) 又需要在 \(p_j\) 之前出栈,那么这就会产生矛盾。

我们预处理 \(\displaystyle f_i = \min_{j = i}^{n} p_j\) ,就可以在 \(O(n ^ 2)\) 的时间内判断一对 \(i, j\) 是否可以共存了(也就是 \(f_{j + 1} < p_i < p_j\) )

然后对于存在两个栈的情况,我们就需要把 \(p\) 划分成两个序列,使得这两个序列之中的数都互不冲突。

这样的话,我们对于一对不能共存的 \(i, j\) 连边,然后进行二分图染色。如果不可染,那么就是不存在一组合法解。

之后我们只需要解决使得最后解字典序最小的限制。

我们染色的时候 BFS 染色,尽量把在前面的放入第一个栈。

然后后面得到操作序列直接模拟肯定是个错的。

举个样例:

5
2 4 1 3 5

标准输出:

a c a b b a b a d b 

前面大部分错误的输出:

a c a b b a b d a b 

为什么呢,因为你向第二个栈 push 后,不一定现在拿出来 pop ,第一个栈中能继续 push

那么我们就贪心一下,我们在 push 之后不马上 pop ,等到需要 pop 的时候再 pop

哪些时候需要 pop 呢,就是这个栈不合法的时候需要 pop (也就是这个栈 栈顶到栈底 不单调递增的时候,不满足单调栈性质)

但是注意向第二个栈中 push 之前,因为第一个栈的 pop 优先级更高,我们看能不能先 pop 第一个栈。

这样就应该是最优的了,注意最后要把两个栈按顺序清空。

代码


#include <bits/stdc++.h>#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define pb push_backusing namespace std;template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }inline int read() {int x(0), sgn(1); char ch(getchar());for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);return x * sgn;
}void File() {
#ifdef zjp_shadowfreopen ("P1155.in", "r", stdin);freopen ("P1155.out", "w", stdout);
#endif
}const int N = 1010, inf = 0x7f7f7f7f;int n, P[N], minv[N], col[N];int pos = 1;
stack<int> S[2];inline void out(char ch) {putchar (ch); putchar (' ');
}inline bool Pop(int id) {if (!S[id].empty() && S[id].top() == pos) {out(id ? 'd' : 'b'), S[id].pop(), ++ pos;return true;}return false;
}inline void Push(int cur, int id) {if (id == 1) { while(Pop(0)); }while (!S[id].empty() && S[id].top() < cur)if (!Pop(id)) Pop(id ^ 1);if (id == 1) { while(Pop(0)); }S[id].push(cur); out(id ? 'c' : 'a');
}vector<int> G[N];int main () {File(); n = read();For (i, 1, n)P[i] = read();minv[n + 1] = n + 1;Fordown (i, n, 1)minv[i] = min(minv[i + 1], P[i]);For (i, 1, n) For (j, i + 1, n) if (minv[j + 1] < P[i] && P[i] < P[j])G[i].pb(j), G[j].pb(i), col[i] = col[j] = -1;For (i, 1, n) if (!~col[i]) {queue<int> Q; Q.push(i); col[i] = 0;while (!Q.empty()) {int u = Q.front(); Q.pop();for (int v : G[u]) {if (~col[v] && col[v] != (col[u] ^ 1)) return puts("0"), 0;if (!~col[v]) Q.push(v);col[v] = col[u] ^ 1;}}}For (i, 1, n)Push(P[i], col[i]);bool flag = true;while (flag) {flag = false;while(Pop(0)) flag = true;while(Pop(1)) flag = true;}return 0;}

转载于:https://www.cnblogs.com/zjp-shadow/p/9831491.html

[NOIp2008] 双栈排序 (二分图染色 + 贪心)相关推荐

  1. LOJ P1155 双栈排序 二分图染色 图论

    https://www.luogu.org/problem/show?pid=P1155 题解: https://www.byvoid.com/zhs/blog/noip2008-twostack 开 ...

  2. NOIP2008 双栈排序

    https://www.luogu.org/problem/show?pid=1155 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输 ...

  3. P1155 双栈排序(二分图染色)

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

  4. P1155 双栈排序(二分图的染色判断+链式前向星)

    P1155 双栈排序 让字典序最小,当然尽量进S1 那什么时候必须进S2呢? a[i]和a[j] 不能压入同一个栈⇔存在一个k,使得i<j<k且a[k]<a[i]<a[j] 因 ...

  5. 虚拟化构建二分图(BZOJ2080 题解+浅谈几道双栈排序思想的题)

    虚拟化构建二分图 ------BZOJ2080 题解+浅谈几道双栈排序思想的题 本题的题解在最下面↓↓↓ 不得不说,第一次接触类似于双栈排序的这种题,是在BZOJ的五月月赛上. [BZOJ4881][ ...

  6. #include NOIP2008 Junior 双栈排序 ——using namespace wxl;

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

  7. #include lt;NOIP2008 Juniorgt; 双栈排序 ——using namespace wxl;

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

  8. 二分图——洛谷P1155 双栈排序

    https://daniu.luogu.org/problem/show?pid=1155 二分图染色+模拟 1.首先考虑一个简单情况--单栈排序,显然有这样的一个事实: a[i]和a[j] 不能压入 ...

  9. 【每日一题】8月7日题目精讲—双栈排序

    来源:牛客网 文章目录 题目描述 题意: 题解: 代码: 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言262144K 64bit IO Format: %l ...

最新文章

  1. Calendar类点点滴滴积累
  2. 三维感知,这些干货足够了!(自动驾驶/三维重建/SLAM/点云/标定/深度估计/3D检测)...
  3. 【原创】new和delete
  4. DotNET企业架构应用实践-企业管理软件架构的历史与发展(中)- 分布式系统
  5. 《SAP CRM管理与实施指南》一一2.2 SAP CRM基础功能
  6. DIB位图(Bitmap)的读取和保存
  7. AV Linux 2016系统今年发布:影音制作专用
  8. 一文搞定 Spring Data Redis 详解及实战
  9. truncate table语句和delete table语句的区别
  10. 小熊的人生回忆(二)
  11. 电子相册系统(六)相片列表显示
  12. 用 grldr 引导WinXP/Ubuntu双系统
  13. eclipse报错 : One or more constraints have not been satisfied.
  14. 注册cad中文件未找到html,acad(2014CAD出现未找到acad文件 求解)
  15. HNOI2015 亚瑟王
  16. 社交媒体中有哪些有趣的数据?能挖掘出哪些价值?
  17. 第九章 思科IOS与华为VRP系统及命令行配置
  18. cent os 安装
  19. appcan.frame.open打开的浮空窗口页面不开启弹动的情况下,也会有微微的滑动bug...
  20. 微型计算机48MHz辐射超,造成EMC辐射超标原因有哪些(精彩案例分析)

热门文章

  1. 服务器计时器、Windows 计时器和线程计时器
  2. 【Vue.js 知识量化】基础语法
  3. 【Spring MVC】学习笔记汇总
  4. RedHat停止维护CentOS!CentOS 创建者发起新项目,刚上线空白项目Star数已破两千
  5. arcgis 4.x graphicslayer点击事件_ArcGis中X、Y值的巧用方法小记
  6. 最近给公司撸了一个可视化大屏
  7. 数据中台不是企业的万能妙药
  8. 财务报表开发实例分析:几个通用维度介绍与关键点
  9. 数据/方法论固然重要,但人为分析更有价值!
  10. Nodejs版本的企业微信中接收消息与腾讯对接之验证URL 代码已经上传,可以去下载