1051 Pop Sequence (25分)用状态转移方程来解,附多组测试样例及生成测试样例的代码
前言
题目不再赘述。目前本题大部分用的是stack模拟出栈的合法性。本文用状态转移方程做了一波,并给出多组测试用例,以及可以用来生成测试样例的代码。
例如不合法序列:1 2 3 4 7 5 6
目前考察元素5的出栈情况。
对于每个将要出栈的元素(5)而言,应当满足:该元素左边的元素(1,2,3,4)可以部分已经出栈,但是剩余元素的个数不得大于栈的深度5。
该元素右边的各个元素(6,7)要么全部都没有出栈,要么全部都已经出栈,再要么最右侧的所有都没出栈,紧邻5的元素们全部都已经出栈。
我们假设尚未进行出栈操作表示为1,已经进行出栈操作表示为0。那么将要出栈的元素右边的元素。合法的状态是:
- 11111111111…全部都没有出栈(出栈序列比当前元素靠后)。比如将要出栈5,那么序列5,(6,7,8,9)可能是一个合法解。
- 000000000…全部都已经出过栈(出栈序列比当前元素靠前)。比如将要出栈5,那么序列(6,7,8,9),5可能是一个合法解。
- 00000…111…最右边的都没出栈,最左边的都已经出过栈。比如将要出栈5,那么序列(6,7),5,(8,9)可能是一个合法序列。
不合法的状态是: - 00000…111111…0000。也就是说(6,7),(11,12),5,(8,9,10)这是一个不合法序列。
- 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