列车调度

列车调度

题目详见: https://dsa.cs.tsinghua.edu.cn/oj/problem.shtml?id=1145
描述

某列车调度站的铁道联接结构如Figure 1所示。
figure 1

其中,A为入口,B为出口,S为中转盲端。所有铁道均为单轨单向式:列车行驶的方向只能是从A到S,再从S到B;另外,不允许超车。因为车厢可在S中驻留,所以它们从B端驶出的次序,可能与从A端驶入的次序不同。不过S的容量有限,同时驻留的车厢不得超过m节。

设某列车由编号依次为{1, 2, …, n}的n节车厢组成。调度员希望知道,按照以上交通规则,这些车厢能否以{a1, a2, …, an}的次序,重新排列后从B端驶出。如果可行,应该以怎样的次序操作?

输入
共两行。
第一行为两个整数n,m。
第二行为以空格分隔的n个整数,保证为{1, 2, …, n}的一个排列,表示待判断可行性的驶出序列{a1,a2,…,an}。

输出
若驶出序列可行,则输出操作序列,其中push表示车厢从A进入S,pop表示车厢从S进入B,每个操作占一行。

若不可行,则输出No。

样例
example 1
Input

5 2
1 2 3 5 4

Output

push
pop
push
pop
push
pop
push
push
pop
pop

example 2
Input

5 5
3 1 2 4 5

Output

No

限制
1 ≤ n ≤ 1,600,000

0 ≤ m ≤ 1,600,000

时间:2 sec

空间:256 MB

思路

这道题其实按我理解,很类似出栈序列的合法性,当然算法很不一样。我说类似判断类似出栈合法性是因为第一次看到题的时候,以为是给你一个乱序序列(12354),让你借助栈,以升序(12345)序列输出。
然而并不是啊!!!所以一直看不懂样例2的no是怎么来的。
纠结了好久,网上看了之后才发现问题所在。然后也发现,这种问题其实叫"栈混洗问题"。
解决方法呢主要是两个一维数组,一个int栈。一维数组seq用来存储待检验的序列。另一个一维数组ans用来存储操作(因为该题如果结果为“No”是不需要输出操作的,所以要先把操作存储,然后根据最后结果判断是否输出),1代表“push",2代表"pop"。
首先搞清楚输出"No"的判断条件:
case1:栈容量溢出。
case2:栈顶元素大于待检测序列的第一位.
然后在n个循环中和seq的元素依次进行比对,若seq的元素大于循环i,那么把i入栈,ans数组增加元素1,直到他俩相等。
如果栈顶元素等于当前seq[i]的元素,那么pop,然后ans数组增加元素0.

代码

如有错误,请多指正

#include <iostream>

using namespace std;
/**********************************
输出NO:
case1:栈容量溢出
case2:栈顶元素大于待检测序列的第一位
**********************************/

template<typename T>
class stack
{
private:
    T* data;
    T top;
    int maxsize;
public:
    stack ( int _max )
    {
        maxsize = _max;
        data = new T[maxsize];
        top = -1;
    }
    void expand()
    {
        int newsize = maxsize * 2;
        T *newdata = new T[newsize];
        for ( int i = 0; i < maxsize; i++ )
            newdata[i] = data[i];
        maxsize = maxsize * 2;
        data = newdata;
    }
    void push ( T x )
    {
        if ( top == maxsize - 1 )
            expand();
        data[++top] = x;
    }
    void pop ()
    {
        if ( top > 0 )
        {
            top--;
        }
    }
    bool empty()
    {
        return top == -1 ? true : false;
    }
    T gettop()
    {
        if ( top != -1 )
            return data[top];
        return -1;
    }
    int size()
    {
        return top + 1;
    }
};

int main()
{
    int m;//序列个数
    int n;//栈容量
    int j = 0;
    int k = 0;//ans的下标
    cin >> m >> n;
    int seq[m];
    int ans[2*m] ;//操作最大为2m
    stack<int> s ( 100 );

    for ( int i = 1; i < m+1; i++ )
        scanf ( "%d", &seq[i] );

    for ( int i = 1; i < m+1; i++ )
    {
        //case2
        if ( seq[i] < s.gettop() && !s.empty())
        {
            printf ( "No\n" );
            return 0;
        }

        if ( seq[i] > j )
        {
            while ( seq[i] != j )
            {
                s.push ( ++j );
                ans[k++] = 1;
            }
        }
        //case1
        if ( s.size() > m )
        {
            printf ( "No\n" );
            return 0;
        }
        if ( s.gettop() == seq[i] )
        {
            s.pop();
            ans[k++] = 0;
        }
    }

    for(int i= 0;i<k;i++)
    {
        if(ans[i])
            printf("push\n");
        else
            printf("pop\n");
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值