洛谷1155:双栈排序

题意描述:

  • 给定一个长度为\(n\)的序列\((n\leq 1000)\),两个初始为空的栈,问是否能借助以下四种操作将序列排为升序。
  • \(1:\)如果序列不为空,将第一个元素压入栈\(S_1\)。记为操作\(a\)。
  • \(2:\)如果栈\(S_1\)不为空,将\(S_1\)栈顶元素弹出至输出序列。记为操作\(d\)。
  • \(3:\)输入序列不为空,将第一个元素压入栈\(S_2\)。记为操作\(c\)。
  • \(4:\) 如果栈\(S_2\)不为空,将\(S_2\)栈顶元素弹出至输出序列。记为操作\(d\)。

输出描述:

  • 输出字典序最小的操作序列,如果不满足双栈排序性质,输出\(0\)。

思路:

  • 写了半天单调栈+贪心+模拟被提醒是二分图。
  • 写一篇题解纪念我逝去的三个小时。
  • 首先有这样一个性质。
  • 如果存在这种情况\(i<j<k\)且\(a(k)<a(i)<a(j)\),那么\(a(i),a(j)\)不能处于同一个栈内,这是一个充分必要条件。
  • 证明:
  • 必要性:如果有\(i<j<k\)且\(a(k)<a(i)<a(j)\),则因为\(a(i)\)和\(a(j)\)后面都存在一个更小的数\(a(k)\),因此\(a(i),a(j)\)都不能从栈中被弹出。所以从栈底到栈顶的元素就不是一个单调递减的降序了,那么弹出的时候就会出现逆序对,因此\(a(i),a(j)\)不能分配到同一个栈中。
  • 充分性:如果\(a(i),a(j)\)不满足上述条件,则在操作过程中一定不会出现矛盾。
    • 所有大于\(a(j)\)的元素,都一定在栈中;
    • 所有小于\(a(j)\)的元素,比如说\(a(i)<a(j)\),则由于后面不存在\(a(k)<a(i)\),因此\(a(i)\)已经出栈。
    • 所以将\(a(j)\)压入栈中,从栈底到栈顶依然可以保持降序,因此整个过程都是可以顺利进行的。
  • 有了上述性质后,我们只需要将所有满足条件的点分到两个栈中,这一步可以转化为图论问题。
  • 枚举所有点对,如果\(i,j\)满足能在一个栈条件,则在\(i,j\)加边。
  • 当然枚举所有点对同时考虑上述条件,会发生一件很糟糕的事情。
    • 我枚举点对需要\(O(n^2)\)的时间复杂度,同时我需要向后扫描找到有没有更小的数字则需要\(O(n)\)的时间复杂度,总共就会要\(O(n^3)\),无法通过。
  • 想办法优化这一步,我们可以预处理\(f(i)=min(a_j)\)。\(j\)从\(i\)到\(n\)。
  • 这样就可以\(O(n^2)\)枚举点对,判断是否有\(i,j\)满足条件,也就是\(f_{j+1}<a_i<a_j\)。
  • 然后判断是否为二分图,从而判断是否能满足双栈排序的性质,可以用染色法。
  • 又因为字典序要求最小,所以优先将点分配到\(S_1\)中。
  • 之后模拟双栈排序,得出答案。

复杂度分析:

  • 建图枚举所有点对\(O(n^2)\)。
  • 染色法判定二分图\(O(n+m)\)。
  • 模拟栈排序\(O(n)\)。
  • 总时间复杂度为\(O(n^2)\),可以通过。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
int n, a[maxn], f[maxn];

int head[maxn], ver[maxn<<5], nex[maxn<<5], tot;
inline void add_edge(int x, int y){
    ver[++tot] = y; nex[tot] = head[x]; head[x] = tot;
}

int color[maxn];
bool dfs(int x, int c)
{
    color[x] = c;
    for(int i = head[x]; i; i = nex[i])
    {
        int y = ver[i];
        if(!color[y])
        {
            if(!dfs(y, 3 - c)) return false;
        }
        else if(color[y] == c) return false;
    }
    return true;
}

int main()
{
    scanf("%d", &n); f[n+1] = INF;
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);

    for(int i = n; i >= 1; i--) f[i] = min(f[i+1], a[i]);

    for(int i = 1; i < n; i++)
        for(int j = i + 1; j < n; j++)
        if(a[i] > f[j+1] && a[i] < a[j])
            add_edge(i, j), add_edge(j, i);

    bool flag = true;
    for(int i = 1; i <= n; i++)
    {
        if(!color[i])
        {
            if(!dfs(i, 1))
            {
                flag = false;
                break;
            }
        }
    }

    if(flag == false) puts("0");
    else
    {
        stack<int> stk1, stk2;

        int cnt = 1;
        for(int i = 1; i <= n; i++)
        {

            if(color[i] == 1)
            {
                stk1.push(a[i]);
                printf("a ");
            }
            else{
                stk2.push(a[i]);
                printf("c ");
            }
            while((!stk1.empty() && stk1.top() == cnt) || (!stk2.empty() && stk2.top() == cnt))
            {
                if(!stk1.empty() && stk1.top() == cnt)
                {
                    stk1.pop();
                    cnt++;
                    printf("b ");
                }
                else
                {
                    stk2.pop();
                    cnt++;
                    printf("d ");
                }
            }
        }
    }
    return 0;
}

luogu_1155: 双栈排序的更多相关文章

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

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

  2. noip2008 双栈排序

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

  3. BZOJ 2080: [Poi2010]Railway 双栈排序

    2080: [Poi2010]Railway Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 140  Solved: 35[Submit][Statu ...

  4. 双栈排序(codevs 1170)

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

  5. #include <NOIP2008 Junior> 双栈排序 ——using namespace wxl;

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

  6. [NOIP2008] 提高组 洛谷P1155 双栈排序

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

  7. 【NOIP2008】双栈排序

    感觉看了题解还是挺简单的,不知道当年chty同学为什么被卡了呢么久--所以说我还是看题解了 原题: Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将 ...

  8. 双栈排序(codevs 1170)题解

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

  9. Noip2008双栈排序

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

随机推荐

  1. teacher笔记

    ======= 总览 start ======= 1.素质教育以提高国民素质为根本宗旨4.素质教育是促进学生个性发展的教育5.素质教育是以培养学生的创新精神和事件能力为重点的教育2.素质教育是面向全体 ...

  2. Docker在linux系统下的安装

    系统要求 本安装教程仅限于CentOS7,其他系统不适用.centos-extras仓库必须是启用状态,这个仓库默认状态是启用,如果不是启用状态,请修改. 卸载旧版本的Docker Docker的旧版 ...

  3. css z-index 的学习

    前言:这是笔者第一次写博客,主要是学习之后自己的理解.如果有错误或者疑问的地方,请大家指正,我会持续更新! z-index属性描述元素的堆叠顺序(层级),意思是 A 元素可以覆盖 B 元素,但是 B ...

  4. HTML 引用大全

    路径logo <link rel="icon" href="../framework7-4.4.10/kitchen-sink/core/img/ztjs.png& ...

  5. SQL server数据库创建代码,filegroup文件组修改,

    以下示例在 SQL Server 实例上创建了一个数据库.该数据库包括一个主数据文件.一个用户定义文件组和一个日志文件.主数据文件在主文件组中,而用户定义文件组包含两个次要数据文件.ALTER DAT ...

  6. C#读写调整设置UVC摄像头画面-亮度

    有时,我们需要在C#代码中对摄像头的亮度进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像 ...

  7. 完全图解 HTTPS

    安全基础 我们先来看下数据在互联网上数据传递可能会出现的三个比较有代表性的问题,其实后面提到的所有方法,都是围绕解决这三个问题而提出来的. 窃听 伪造 否认 对称密钥加密 假设 A 正在通过互联网向  ...

  8. selenium自学笔记---ecshop购买脚本 xpath定位元素(下拉框,单选框)

    本机环境:xamppv3.2.1+ecshop3.0  1.元素定位写对,却一直报错,发现是页面元素加载的太慢,所以加上延时 from selenium import webdriverimport ...

  9. 阿里和Google的JAVA开发规约

    <阿里 JAVA开发规约> 阿里巴巴Java开发手册终极版v1.3.0.pdf 出处:github地址:https://github.com/alibaba/p3c <Google ...

  10. 浏览器标签页切换时jquery动画的问题

    最近公司在做大屏设备上的页面,其中动画的部分居多,开始的时候是用的jquery做的动画,在做完后无意中发现jquery动画存在一个问题,就是浏览器在切换标签页后,过段时间切换回来页面中的动画会出现连续 ...