• luoguP1155 双栈排序


    题目描述

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

    操作a
    如果输入序列不为空,将第一个元素压入栈S1
    操作b
    如果栈S1不为空,将S1栈顶元素弹出至输出序列
    操作c
    如果输入序列不为空,将第一个元素压入栈S2
    操作d
    如果栈S2不为空,将S2栈顶元素弹出至输出序列

    输入输出格式

    输入格式:
    输入文件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

    分析:
    第一眼看过去,很简单啊,模拟一下就好了
    只要遵循:
    在栈里的元素一定是单调递减的
    栈里相邻元素相差的越少越好,
    优先选择第一个栈
    实测:40分
    这完全就是钻制度的空子。。。

    好吧,说正经的

    考虑a[i],a[j]两个元素不能进入同一个栈的条件.
    注意,这里所说的”a[i],a[j]两个元素不能进入同一个栈“,
    是自始至终不能进入一个栈,
    即如果有解,那么a[i],a[j]一定进入过的栈不同.

    条件:存在k使得i < j < k且a[k] < a[i] < a[j]
    进栈顺序i->j->k
    栈中的元素一定是单调减的
    如果ta们在一个栈中,那么进栈顺序是j->i->k,与原命题矛盾

    那知道了这个有什么用呢
    我们可以知道元素两两能不能在一起,
    如果i和j不能在一起,j和k不能在一起,i和k不能在一起,那原序列无解

    我们把不能在一起的一对点之间连边
    (突然觉得这蜜汁像关押罪犯,当有冲突时,就把边两端的点分配到不同的集合中去)
    之后遍历一遍进行01染色
    这样我们知道了进栈的状况,就可以直接模拟输出了
    (直接上40分的骗分)

    tip

    按理说在处理冲突点对的时候是O(n^3)的复杂度,对于1000太大了,大神说要用dp优化一下,但是luogu数据实在是太耿直了,打的三方暴力就这样A了

    简单说一下dp优化,
    因为我们只要找到一个k满足就判定是冲突点对,
    所以设f[i]表示i-n中的最小值
    如果最小值都满足不了那就不可能了
    这样可以把k的循环降到O(1)

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<queue>
    
    using namespace std;
    
    const int N=1010;
    int n,a[N];
    char s[N];
    struct node{
        int x,y,nxt;
    };
    node way[N<<1];
    int st[N],tot=0,co[N],st1[N],st2[N];
    
    void add(int u,int w)
    {
        tot++;
        way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;
        tot++;
        way[tot].x=w;way[tot].y=u;way[tot].nxt=st[w];st[w]=tot;
    }
    
    void doit()
    {
        int i,j;
        memset(co,-1,sizeof(co));
        queue<int> q;
        q.push(way[1].x);
        co[way[1].x]=0;
        while (!q.empty())   //染色 
        {
            int r=q.front();
            q.pop();
            for (i=st[r];i;i=way[i].nxt)
            {
                if (co[way[i].y]==-1) 
                {
                    co[way[i].y]=(co[r]==0 ? 1:0);
                    q.push(way[i].y);
                }
                else if (co[way[i].y]==co[r])
                {
                    printf("0
    ");
                    return;
                }
            }
        }
        int t=-1,t1=0,t2=0,k=1;
        for (i=1;i<=n;i++)
        {
            if (a[k]==i)
            {
                printf("a b ");k++;
                continue;
            }
            if (st1[t1]==i)
            {
                printf("b "); t1--; continue;
            }
            if (st2[t2]==i)
            {
                printf("d "); t2--; continue;
            }
            while (a[k]!=i)
            {
                if (co[k]==0||co[k]==-1)
                   printf("a "),st1[++t1]=a[k];
                else printf("c "),st2[++t2]=a[k];
                k++;
            }
            printf("a b ");k++;
        }
        return; 
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for (int i=1;i<n-1;i++)  //i<j<k  a[k]>a[i]>a[j]
            for (int j=i+1;j<n;j++)
            {           
                if (a[i]<a[j])
                for (int k=j+1;k<=n;k++)
                    if (a[k]<a[i])
                    {
                        add(i,j);break;
                    } 
            }
        doit();
        return 0;
    }
  • 相关阅读:
    Jmeter实际操作
    Windows+JMeter+InfluxDB+Grafana搭建可视化实时监控
    c# 新语法
    js 判断打印或取消 打印插件
    BACnet协议
    串口偶尔出现串口乱码原因
    面向流程葵花宝典
    lwip框架示意图
    linux 算法介绍
    什么是序列化与反序列化
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673443.html
Copyright © 2020-2023  润新知