• P1155 双栈排序


    本来以为是一道排序题,然而看了一眼标签

    woc,图论题,一脸懵逼~~~~~~

    题意:给你两个栈,四种操作

    操作 a

    如果输入序列不为空,将第一个元素压入栈 $S_1$

    操作 b

    如果栈$S_1$不为空,将$S_1$ 栈顶元素弹出至输出序列

    操作 c

    如果输入序列不为空,将第一个元素压入栈$S_2$

    操作 d

    如果栈 $S_2$ 不为空,将$S_2$ 栈顶元素弹出至输出序列

    然后,给你1-n的一个全排列,问能否双栈排序

    能:输出字典序最小的操作序列,否则输出0

    正解:二分图染色 --------------------by@ Harry·Shaun·Wang(lg)

    1.首先考虑一个简单情况:单栈排序:

    若存在一个k,使得i<j<k且a[k]<a[i]<a[j],则a[i]和a[j]不能压入一个栈中

    用f[i]维护后缀最小值

    状态:f[i]=min(a[i],a[i+1], ... ,a[n])

    边界条件:f[n+1]=INF;

    状态转移方程:f[i]=min(f[i+1],a[i]);

    于是上述判断就转化为了f[j+1]<a[i] && a[i]<a[j]

    把时间复杂度从$O(n^3)$优化到了$O(O^2)$

    2.扩展到双栈排序:

    如果a[i]和a[j]不能在一个栈内,即连接一条i与j之间的无向边,接下来我们只需要判断这个图是否为二分图

    由于题目中说编号的字典序要尽可能的小,那么就把编号小的尽可能放到stack1

    判断二分图的方法可以采用黑白染色的方式,先从编号小的开始染,第一个顶点染成黑色,相邻的顶点染成不同的颜色,如果发现黑白冲突,那么说明这个图不是一个二分图,是不合法的,输出0.

    (DFS或BFS染色均可)

    3.染色后所有黑色的点进stack1,所有白色的点进stack2,最后模拟输出过程就可以了.

    详见代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    #define olinr return
    #define love_nmr 0
    #define _ 0
    int f[1050];
    int xl[1050];
    int n;
    int col[1050];
    vector<int> G[1050];
    queue<int> q;
    struct node
    {
        int st[1050];
        int tp;
        node()
        {
            memset(st,0,sizeof st);
            tp=0;
        }
        void pop()
        {
            tp--;
        }
        void push(int x)
        {
            tp++;
            st[tp]=x;
        }
        bool empty()
        {
            return tp==0;
        }
        int top()
        {
            return st[tp];
        }
    };
    node A;
    node B;
    /*----------------------------olinr love nmr---------------------------------------*/
    inline void bfs(int now)
    {
        while(!q.empty()) q.pop();
        q.push(now);
        col[now]=1;
        while(!q.empty())
        {
            int tp=q.front();
            q.pop();
            int siz=G[tp].size();
            for(int i=0;i<siz;i++)
            {
                int go=G[tp][i];
                if(col[go]==-1) 
                {
                    col[go]=col[tp]^1;
                    q.push(go);
                }
                else if(!(col[go]^col[tp]))
                {
                    cout<<0;
                    exit(0);
                }
            }
        }
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin>>n;
        f[n+1]=0x7fffffff;
        for(int i=1;i<=n;i++)
            cin>>xl[i];
        for(int i=n;i>=1;i--)
            f[i]=min(f[i+1],xl[i]);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
            {
                if(xl[i]>f[j+1]&&xl[i]<xl[j])
                {
                    G[i].push_back(j);
                    G[j].push_back(i);
                }
            }
        memset(col,-1,sizeof col);
        for(int i=1;i<=n;i++)
            if(col[i]==-1)
                bfs(i);
        int tot=1;
        for(int i=1;i<=n;i++)
        {
            if(col[i]==1)
            {
                cout<<"a ";
                A.push(xl[i]);
            }
            else
            {
                cout<<"c ";
                B.push(xl[i]);
            }
            while((!A.empty()&&A.top()==tot)||(!B.empty()&&B.top()==tot))
            {
                if((!A.empty()&&A.top()==tot))
                {
                    A.pop();
                    cout<<"b ";
                }
                else
                {
                    B.pop();
                    cout<<"d ";
                }
                tot++;
            }
        }
        olinr ~~(0^_^0)+love_nmr;
    }
  • 相关阅读:
    mysql/mariadb基于ssl的主从复制
    原创工具binlog2sql:从MySQL binlog得到你要的SQL
    [转]MySQL DBA面试全揭秘
    mysql my.cnf 配置建议
    mysql配置文件 /etc/my.cnf 详细解释
    [转]expect实现ssh自动交互
    Linux中的lo回环接口详细介绍
    Docker最全教程——从理论到实战(五)
    Docker最全教程——从理论到实战(四)
    Docker最全教程——从理论到实战(一)
  • 原文地址:https://www.cnblogs.com/olinr/p/9485808.html
Copyright © 2020-2023  润新知