1002. 双栈排序

18 篇文章 0 订阅
13 篇文章 0 订阅

题目要求

Description
Tom最近在研究一个有趣的排序问题。如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序。
操作a
如果输入序列不为空,将第一个元素压入栈S1
操作b
如果栈S1不为空,将S1栈顶元素弹出至输出序列
操作c
如果输入序列不为空,将第一个元素压入栈S2
操作d
如果栈S2不为空,将S2栈顶元素弹出至输出序列
如果一个1~n的排列P可以通过一系列操作使得输出序列为1,2,…,(n-1),n,Tom就称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希望知道其中字典序最小的操作序列是什么。
Input
输入有多组Case,每个Case第一行是一个整数n(n<=1000)。
第二行有n个用空格隔开的正整数,构成一个1~n的排列。
Output
每组Case输出一行,如果输入的排列不是“可双栈排序排列”,输出数字0;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
Sample Input
Copy sample input to clipboard
4
1 3 2 4
4
2 3 4 1
Sample Output
a b a a b b a b
0

思考

代码

// Problem#: 19143
// Submission#: 4809694
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <iostream>
#include <stack>
#include <cmath>
#include <cstdlib>
#include <string>
#define max 1000 + 1
using namespace std;

int input[max];
// the min num after each pos
int inputMin[max];
bool edge[max][max];
// 0 for initial, 1 for s1, 2 for s2
// (3 - color) for calculate the other color
int color[max];
stack<int> s1, s2;
bool isUnable;
void initialize() {
    while(!s1.empty()) s1.pop();
    while(!s2.empty()) s2.pop();
    for (int i = 0; i < max; i++) {
        input[i] = color[i] = inputMin[i] = 0;
        for (int j = 0; j < max; j++) {
            edge[i][j] = false;
        }
    }
    isUnable = false;
}

void calMIN(int size) {
    for (int i = size - 1; i >= 0; i--) {
        if (i == size - 1)
            inputMin[i] = input[i];
        else inputMin[i] = min(input[i], inputMin[i + 1]);
    }
}

void linkEdge(int size) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = i + 1; j < size; j++) {
            if (input[i] < input[j] && inputMin[j] < input[i]) {
                edge[i][j] = edge[j][i] = true;
            }
        }
    }
}

void dfs_dye(int pos, int _color, int size) {
    color[pos] = _color;
    for (int i = 0; i < size; i++) {
        if (edge[pos][i]) {
            if (color[i] == _color) {

                isUnable = true;
                break;
            } else if (color[i] == 0){
                dfs_dye(i, 3 - _color, size);
            }
        }
    }
}
void dye(int size) {
    for (int i = 0; i < size; i++) {
        if (color[i] == 0) {
            dfs_dye(i, 1, size);
        }
    }
}

void stackSort(int size) {
    if (isUnable) {
        cout << "0" << endl;
        return;
    } 
    int current = 1;
    string s;
    for (int i = 0; i < size; i++) {
        if (color[i] == 1) {
            s1.push(input[i]);
            s += "a ";
        } else {
            s2.push(input[i]);
            s += "c ";
        }
        while ((!s1.empty() && s1.top() == current) ||
               (!s2.empty() && s2.top() == current)) {
            if (!s1.empty() && s1.top() == current) {
                s1.pop();
                s += "b ";
            } else {
                s2.pop();
                s += "d ";
            }
            current++;
        }
    }
    for (int i = 0; i < s.size() - 1; i++) cout << s[i];
    cout << endl; 
}

int main() {
    int n;
    while (cin >> n) {
        if (n > 0) {
            // initialize
            initialize();
            // read data
            for (int i = 0; i < n; i++) cin >> input[i];
            // processing
            calMIN(n);
            linkEdge(n);
            dye(n);
            stackSort(n);
        }
    }
    return 0;
}                                 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值