• P1155 双栈排序


    题目描述

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

    操作aaa

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

    操作b

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

    操作c

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

    操作d

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

    如果一个1−n的排列P可以通过一系列操作使得输出序列为1,2,…,(n−1),nTom就称P是一个“可双栈排序排列”。例如(1,3,2,4)就是一个“可双栈排序序列”,而(2,3,4,1)不是。下图描述了一个将(1,3,2,4)排序的操作序列:<a,c,c,b,a,d,d,b>

    当然,这样的操作序列有可能有几个,对于上例(1,3,2,4)<a,c,c,b,a,d,d,b>是另外一个可行的操作序列。Tom希望知道其中字典序最小的操作序列是什么。

    输入输出格式

    输入格式:

    第一行是一个整数n

    第二行有n个用空格隔开的正整数,构成一个1−n的排列。

    输出格式:

    共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。

    输入输出样例

    输入样例#1: 
    4
    1 3 2 4
    输出样例#1: 
    a b a a b b a b
    输入样例#2: 
    4
    2 3 4 1
    输出样例#2: 
    0
    输入样例#3: 
    3
    2 3 1
    输出样例#3: 
    a c a b b d

    说明

    30%的数据满足: n≤10

    50%的数据满足:n≤50

    100%的数据满足: n≤1000

    Solution:

      本题二分图染色+栈模拟。  

      若我们知道每个数应该放在哪个栈中,就可以去模拟了。

      考虑数$a_i,a_j,a_k$不能在同一栈的情况,若$i<j<k,a_i<a_j,a_i>a_k$那么$i,k$是肯定不能在同一栈内的,我们对二元组建边,那么就是个二分图染色的模型了。

      由于要字典序最小,所以每次染色时另当前未被染色的位置为栈1再去dfs,染色后每个位置所在的栈就确定了。

      然后就是纯模拟咯。

      (安利一个神奇的调试技巧:用iostream库下的cerr代替cout,在评测机测试时会直接跳过这条输出语句,但在终端可以输出,这样就能防止忘记删调试语句而写挂!>.^_^.<)

    代码:

    /*Code by 520 -- 9.5*/
    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    #define RE register
    #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    const int N=1005;
    int n,a[N],minn[N],col[N];
    int to[N],net[N],h[N],cnt;
    int stk1[N],stk2[N],top1,top2;
    
    il void add(int u,int v){to[++cnt]=v,net[cnt]=h[u],h[u]=cnt;}
    
    bool dfs(int u){
        for(RE int i=h[u];i;i=net[i])
            if(!col[to[i]]) {
                col[to[i]]=col[u]^1;
                if(!dfs(to[i]))return 0;
            }
            else if(col[to[i]]==col[u]) return 0;
        return 1;
    }
    
    int main(){
        ios::sync_with_stdio(0);
        cin>>n,minn[n+1]=0x7fffffff;
        For(i,1,n) cin>>a[i];
        Bor(i,1,n) minn[i]=min(minn[i+1],a[i]);
        For(i,1,n) For(j,i+1,n) if(a[i]>minn[j+1]&&a[i]<a[j]) add(i,j),add(j,i);
        For(i,1,n) if(!col[i]) {
            col[i]=2;
            if(!dfs(i))cout<<0,exit(0);
        }
        For(i,1,n) cerr<<col[i]<<' ';cerr<<endl;
        int cnt=1;
        For(i,1,n){ 
            if(col[i]==2) stk1[++top1]=a[i],cout<<"a ";
            else stk2[++top2]=a[i],cout<<"c ";
            while(top1&&stk1[top1]==cnt||top2&&stk2[top2]==cnt){
                if(stk1[top1]==cnt) cout<<"b ",--top1;
                else cout<<"d ",--top2;
                ++cnt;
            }
        }
        return 0;
    }
  • 相关阅读:
    修改VNC的分辨率
    How to use WinSCP with public key authentication
    CentOS-7-x86_64-DVD-1511.iso
    6.828
    Tampermonkey版Vimium
    servlet+jsp完成简单登录
    Servlet知识点小结
    HTTP基础知识点小结
    LeetCode 371两数之和
    LeetCode53 最大子序列问题
  • 原文地址:https://www.cnblogs.com/five20/p/9595083.html
Copyright © 2020-2023  润新知