1051 Pop Sequence
大致题意就是给出栈的容量M,给出入栈序列的最大元素N(默认入栈顺序是1,2,3,...N), 给出K个可能的出栈序列,判断出栈序列是否合法,合法输出“YES”,否则,输出“NO”。
第一种方法。
首先给出一个结论(以前刷408练习题时看到的):
出栈序列中每个元素的后面的所有比它小的元素,一定可以组成一个递减序列并且该序列中的元素个数一定小于栈的最大容量。
假设栈的容量M为5,N为7(入栈顺序是1,2,3,4,5,6,7)。
1.出栈序列为 3 2 1 7 5 6 4。
因为元素7 后面所有比它小的元素5 6 4不是一个递减序列,所以出栈序列不合法。
2.出栈序列为7 6 5 4 3 2 1.
虽然元素7后面所有比它小的元素 6 5 4 3 2 1是一个递减序列,但是该序列的元素个数是6,大于栈的容量5,所以出栈序列不合法。
#include<iostream> using namespace std; int a[1010] = {0}; int main() { int m,n,k; scanf("%d%d%d",&m,&n,&k); while(k--) { for(int i = 0; i < n; ++i) scanf("%d",&a[i]); bool flag = true; for(int i = 0; i < n && flag == true; ++i) { if(a[i] > 2) { flag = true; int min = a[i],cnt = 0; for(int j = i+1; j < n && flag == true; ++j) { if(a[j] < a[i]) { if(min > a[j]) { //递减序列的最小元素与要加入序列的元素比较 min = a[j]; cnt++;//统计递减序列的元素个数 if(cnt == m) flag = false; } else flag = false; } } } } if(flag == false) printf("NO\n"); else printf("YES\n"); } return 0; }
第二种方法。
在模拟入栈和出栈过程中,判断给定的出栈序列是否合法。
比如 3 2 1 7 5 6 4
入栈1,入栈2,入栈3,出栈3,出栈2,出栈1,入栈4,入栈5,入栈6,入栈7,出栈7,此时栈顶是6,与出栈5不匹配。
再比如1 2 3 4 5 6 7
入栈1,出栈1,入栈2,出栈2,入栈3,出栈3,入栈4,出栈4,入栈5,出栈5,入栈6,出栈6.
总结思路就是,元素在入栈过程中,如果满足条件,即当前栈顶元素与出栈序列的元素相同,那么就出栈该元素,同时把指向出栈序列的元素的下标向后移动一位。如果不满足条件,那么依然继续入栈后面的元素,但是模拟入栈和出栈结束后,栈非空,那么出栈序列就是非法的。
#include<iostream> #include<stack> using namespace std; stack<int> st; int a[1010] = {0}; int main() { int m,n,k; scanf("%d%d%d",&m,&n,&k); while(k--) {//k次查询 while(!st.empty())//栈非空,就清空栈 st.pop(); for(int i = 1; i <=n; ++i) //读入数据 scanf("%d",&a[i]); bool flag = true; int current = 1; //指向出栈序列中的待出栈元素 for(int i = 1; i <= n && flag == true; ++i) { if(st.size() == m) { //栈满 flag = false; break; } st.push(i); //栈顶元素与出栈序列当前位置的元素相同时 while(!st.empty() &&st.top() == a[current]) { st.pop();//循环弹出并令current++ current++; } } if(flag == true && st.size() == 0) printf("YES\n"); //栈空且入栈过程中始终不超出栈的容量 else printf("NO\n"); } return 0; }