Pop Sequence

题目

题目描述

Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, ..., N and pop randomly. You are supposed to tell if a given sequence of numbers is a possible pop sequence of the stack. For example, if M is 5 and N is 7, we can obtain 1, 2, 3, 4, 5, 6, 7 from the stack, but not 3, 2, 1, 7, 5, 6, 4.

输入格式

Each input file contains one test case. For each case, the first line contains 3 numbers (all no more than 1000): M (the maximum capacity of the stack), N (the length of push sequence), and K (the number of pop sequences to be checked). Then K lines follow, each contains a pop sequence of N numbers. All the numbers in a line are separated by a space.

输出格式

For each pop sequence, print in one line "YES" if it is indeed a possible pop sequence of the stack, or "NO" if not.

输入样例

5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2

输出样例

YES
NO
NO
YES
NO

解析

第一次的思路

 说实话我自己都有点...有点歪打正着,以下正文
 写出来非常有成就感的一道题,更加深了对栈的理解,所以觉得值得记录一下~
 算起来真正写程序加调试花了不过四十分钟,但是构建思路的时候花了足足两三个小时吧。
 首先见到题目的第一眼脑海中浮现的就是最直接的也是最蠢的办法:把所有可能的出栈序列都列出来存起来,然后再一一匹配。不过这个想法一出来就被否定了…工作量太大不说,穷举出所有可能序列的算法就够杀死我好多脑细胞了。
 然后关键来了,我又想到了【最大子列和问题】中的*【在线处理】思想,划重点。即每输入一个数据就根据一定的【规则】判断该数据是否为可能的出栈数,如果有一个不满足就可以直接判定该序列不可能。就像其他的在线处理一样,最难的地方想来就是找出这个【规则】。
 在受到了一些大佬思路启发、写写画画用掉了两张草稿纸以及薅掉了自己若干根头发后,终于被我想出来了….
 如何根据上一个出栈数判断本出栈数是否合法呢?
 第一个出栈只要不大于栈容量即可,按下不表。
 剩下的每一个出栈数应当分为两种情况:

  1. 比上一个出栈数大
     对第一种情况而言,应当满足的是在栈容量范围内,即 出栈元素 < 容量 + 出栈次数 + 1,就是说最大可以为容量 + 出栈次数。在推导的时候借助了已入栈最大数,出栈元素 < 最大入栈数 + 容量剩余 + 1,其中 容量剩余 = 容量 - (最大入栈数 - 出栈次数),整理两个式子发现已入栈最大数被抵消了。最终就能得出:出栈元素 < 容量 + 出栈次数 + 1。其实也能理解,第一次的最大元素就是容量,每一次出栈就会空出一个位置让最大元素加一,所以最大元素是容量 + 出栈次数也就合情合理了。
  2. 比上一个出栈数小
     对第二种情况而言,应当满足的是小于上一个出栈数的相近数,如果该数已经出栈那就再往前推。;例如前一个出栈数是7的话,本次出栈数要么就是6,如果6在之前已经出栈了,那就往前推,本次出栈数应该是5,如果5也已经出栈了处理方法相同。

代码

#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char * argv[]) {
    int Max;
    int Num;
    int K;
    scanf("%d %d %d", &Max, &Num, &K);
    int test[Num];
    int i, j, k;
    int flag = 0;
    int flag1;
    for (i = 0; i < K; i++) {
        flag1 = 1;
        for (j = 0; j < Num; j++) {
            scanf("%d", &test[j]);
            if (j == 0 && test[0] > Max){			//第一个出栈的元素
                for (k = 1; k < Num; k++)	
                    scanf("%d", &test[k]);
                break;
            }
            else if (j != 0) {						//非第一个出栈的元素
                if (test[j] > test[j - 1]) {		//比上一个出栈元素大
                    if (test[j] < Max + j + 1)		//判断是否大于容量
                        flag1++;				
                }
                else if (test[j] < test[j - 1]) {	//比上一个出栈元素小
                    int temp;
                    temp = test[j - 1] - 1;			//上一个出栈元素减一
                    for (k = 0; k < j; k++){		//对所有出栈元素进行遍历
                        if (test[k] == temp) {		//判断上一个出栈元素的下一个是否已经出栈
                            temp--;	
                            flag++;
                            k = -1;
                        }
                    }
                    if (test[j] == test[j - 1] - 1 - flag)	//上一个出栈元素减一减去上一个出栈元素
                        flag1++;
                    flag = 0;						//重置flag
                }
            }
        }
        if (flag1 == Num)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

第二次思路

 模拟出栈过程,逐个将1~M压入栈中。入栈过程中如果有和出栈元素一样的就出栈,再检查下一个出栈元素,如果触发错误条件就中止。
 错误条件有二:

  1. 栈中总数大于栈容量;
    这个好理解,超出栈容量了
  2. 出栈元素小于栈顶元素。
     因为是按顺序入的栈,所以比栈顶元素小的元素肯定已经入过栈了,要么在栈中,要么已经出栈了。已经出栈了当然不能再出栈了,按下不表;如果在栈中的话根本不可能跨过栈顶元素出栈。所以这种情况错误

伪代码

	空栈;
	逐个分析出栈序列{
		如果出栈元素大于栈顶元素{
			继续入栈直至栈顶元素等于出栈元素;
				每次入栈时检查是否大于栈容量;
			出栈;
			}
		如果出栈元素等于栈顶元素;
			出栈;
		如果出栈元素小于栈顶元素;
			错误;
	}

代码

#include<iostream>
#include<vector>
#include<stack>
using namespace std;

const int MaxSize = 1005;

int main() {
	int M, N, K;
	int seq[MaxSize];
	stack<int> sta;
	int flag, num;
	cin >> M >> N >> K;

	for (int i = 0; i < K; i++) {
		//重置栈
		num = 0;
		flag = 1;
		while (!sta.empty())
			sta.pop();
		//输入
		for (int j = 0; j < N; j++)
			cin >> seq[j];
		//检测
		for (int j = 0; j < N; j++) {
			while (sta.empty())
				sta.push(++num);
			if (seq[j] > sta.top()) {
				while (seq[j] != sta.top()) {
					sta.push(++num);
					if (sta.size() > M)
						flag = 0;		//错误条件一
				}
				sta.pop();
			}
			else if (seq[j] == sta.top())
				sta.pop();
			else {
				flag = 0;				//错误条件二
				break;
			}
		}
		//输出结果
		if (flag == 0)
			cout << "NO" << endl;
		else
			cout << "YES"<<endl;
	}
}
posted @ 2020-04-11 11:13  游芒。  阅读(162)  评论(0)    收藏  举报