1051 Pop Sequence (25分)判断出栈队列合法性。附多组测试样例,及生成测试样例的代码

1051 Pop Sequence (25分)用状态转移方程来解,附多组测试样例及生成测试样例的代码

前言

题目不再赘述。目前本题大部分用的是stack模拟出栈的合法性。本文用状态转移方程做了一波,并给出多组测试用例,以及可以用来生成测试样例的代码。
例如不合法序列:1 2 3 4 7 5 6
目前考察元素5的出栈情况。
对于每个将要出栈的元素(5)而言,应当满足:该元素左边的元素(1,2,3,4)可以部分已经出栈,但是剩余元素的个数不得大于栈的深度5。
该元素右边的各个元素(6,7)要么全部都没有出栈,要么全部都已经出栈,再要么最右侧的所有都没出栈,紧邻5的元素们全部都已经出栈。
我们假设尚未进行出栈操作表示为1,已经进行出栈操作表示为0。那么将要出栈的元素右边的元素。合法的状态是:

  1. 11111111111…全部都没有出栈(出栈序列比当前元素靠后)。比如将要出栈5,那么序列5,(6,7,8,9)可能是一个合法解。
  2. 000000000…全部都已经出过栈(出栈序列比当前元素靠前)。比如将要出栈5,那么序列(6,7,8,9),5可能是一个合法解。
  3. 00000…111…最右边的都没出栈,最左边的都已经出过栈。比如将要出栈5,那么序列(6,7),5,(8,9)可能是一个合法序列。
    不合法的状态是:
  4. 00000…111111…0000。也就是说(6,7),(11,12),5,(8,9,10)这是一个不合法序列。
  5. 11111…0000…。即(8,9,10),5,(6,7)这是一个不合法序列。
    状态0:000…,加0转至状态0,加1转至状态1。
    状态1:000…111…,加0转至状态2,加1转至状态1.
    状态2:000…111…000…已经非法,不管加0加1都是非法状态。可以与状态4合并。为了简便理解,这里不做合并。加0加1转至状态2。
    状态3:111…,加0转至状态4,加1转至状态3.
    状态4:111…000…,状态已经非法,不管加0加1都是非法状态,全部转移至状态4。
int stateTransfer[5][2] = { {0,1},{2,1},{2,2},{4,3},{4,4}};
//
//省略部分代码
//
int state;
if (check[t + 1] == -1)state = 3;
else state = 0;
for (int s = t + 2; s <= n; s++) {
	state = stateTransfer[state][check[s]==-1];
}
if (state==2 || state == 4) {
	flag = 0;
	continue;
}
else {
	check[t] = 0;
}


1.AC代码如下

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
int check[1010];
int appear[1010];
int stateTransfer[5][2] = { {0,1},{2,1},{4,4},{4,3},{4,4} };

int main()
{
	int m, n, k, t;
	scanf("%d%d%d", &m, &n, &k);
	for (int i = 0; i < k; i++) {
		int flag = 1;
		memset(check+1, -1, 4*n);
		memset(appear + 1, 0, 4 * n);
		for (int j = 0; j < n; j++) {
			scanf("%d", &t);
			if (!flag)continue;
			if (appear[t]) {
				flag = 0;
				continue;
			}
			else {
				appear[t] = 1;
			}
			int num = 1;
			for (int s = t - 1; s >= 1; s--) {
				num -= check[s];
			}
			if (num > m) {
				flag = 0;
				continue;
			}
			// 查看右边是否有非法状态
			int state;
			if (t == n) {
				check[t] = 0;
				continue;
			}
			if (check[t + 1] == -1) {
				state = 3;
			}
			else {
				state = 0;
			}
			for (int s = t + 2; s <= n; s++) {
				state = stateTransfer[state][check[s] == -1];
			}
			if (state == 2 || state == 4) {
				flag = 0;
				continue;
			}
			else {
				check[t] = 0;
			}

		}
		if (flag) {
			printf("YES\n");
		}
		else {
			printf("NO\n");
		}
	}
	return 0;
}

2. 生成测试数据的代码

// 创作By:zhangwenniu@163.com,转载请注明出处。

// 1051.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <cstring>
#include <stack>
#include <algorithm>
using namespace std;
int check[1010];
int appear[1010];
int a[1010] = {0, 1,2,3,4,5,6,7 };
int stateTransfer[5][2] = { {0,1},{2,1},{2,2},{4,3},{4,4} };

stack<int> st;

// 可以在这里将my函数改成你自己写的函数,来判断是否正确
int my(int m, int n) {
	int flag = 1;
	memset(check + 1, -1, 4 * n);
	memset(appear + 1, 0, 4 * n);
	for (int j = 1; j <= n; j++) {
		int t = a[j];
		if (!flag)continue;
		if (appear[t]) {
			flag = 0;
			continue;
		}
		else {
			appear[t] = 1;
		}
		int num = 1;
		for (int s = t - 1; s >= 1; s--) {
			num -= check[s];
		}
		if (num > m) {
			flag = 0;
			continue;
		}
		// 查看右边是否有状态101
		int state;
		if (t == n) {
			check[t] = 0;
			continue;
		}
		if (check[t + 1] == -1) {
			state = 3;
		}
		else {
			state = 0;
		}
		for (int s = t + 2; s <= n; s++) {
			state = stateTransfer[state][check[s]==-1];
		}
		if (state==2 || state == 4) {
			flag = 0;
			// 输出不合法序列。
			printf("t = %d, state = %d. \n", t, state);
			for (int i = 1; i <= n; i++) {
				printf("%d ", a[i]);
			}
			printf("\n");
			continue;
		}
		else {
			check[t] = 0;
		}
		
	}
	return flag;
}

// 市面上常见的用栈模拟的算法,可以用来验证是否正确
int byStack(int n, int m, int o) {
	int flag = 1;
	while (!st.empty()) {
		st.pop();
	}
	int id = 1;
	for (int i = 1; i <= n; i++) {
		st.push(i);
		if (o) {
			printf("i = %d, id = %d, a[%d] = %d. \n", i, id, id, a[id]);
			stack<int> copy = st;
			while (!copy.empty()) {
				printf("%d ", copy.top());
				copy.pop();
			}
			printf("\n");
		}


		if (st.size() > m) {
			if (o) {
				printf("st.size()>m, st.size() = %d, m = %d.\n", st.size(), m);
			}
			flag = 0;
			break;
		}
		while (!st.empty() && st.top() == a[id]) {
			st.pop();
			id++;
		}
	}
	if (flag && st.empty()) {
		return 1;
	}
	else {
		if (o) {
			printf("flag = %d.\n", flag);
			printf("st.empty() == %d\n", st.empty());
			while (!st.empty()) {
				printf("%d ", st.top());
				st.pop();
			}
			printf("\n");
		}
		return 0;
	}

}


int main() {
	int n, m, k;
	n = 7;
	m = 5;
	int id = 0;
	do {
		if (id % 100000==0) {
			printf("id = %d.\n", id);
		}
		id++;
		int f1 = my(m, n);
		int f2 = byStack(n, m,0);
		if (f1 != f2) {
			printf("\n\nf1 = %d, f2 = %d.\n", f1, f2);
			for (int i = 1; i <= 7; i++) {
				printf("%d ", a[i]);
			}
			printf("\n");
			byStack(n, m, 1);
		}
	} while (next_permutation(a+1, a + 8));

}


大量测试用例

下面给出的所有用例全部是非法出栈队列,以供参考。

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

1051通过截图

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ProfSnail

谢谢老哥嗷

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值