题目链接:https://vjudge.net/problem/UVA-514
题目分析
题目的意思是给一个栈输入一系列数据,在这个过程中可以出栈,看能否达到某个结果。
刚开始我觉得这个情况好多,因此不是用模拟,而应该观察结果本身。对于结果中某个元素x
,比他小的元素肯定已经入过栈了,此时可能有两种去处:
- 已经在结果里面了
- 还在栈里面
对于1.,只能说它比x
小而且在x
的前面,除此之外没有其他约束了。
对于2.,那些比x
小的元素在结果中的位置肯定在x
的后面,而且肯定是逆序排列。因为只能进栈一次,而他们是从小到大进栈的,必然是从大到小出栈的。如果不符合这个条件肯定就是非法情况。
我的思路就是检查每个元素后面比他小的元素是否是逆序的,复杂度是O(n2)O(n^2)O(n2)
UVa里面有时候要求最后有换行,有时候又要求不能有空行,真是让人摸不着头脑。。
AC代码
#include <iostream>
#include <vector>
#include <deque>using namespace std;int n;
vector<int> arr;bool check_idx(int idx) {int x = arr[idx];int minx = x;for (int i = idx + 1; i < n; ++i) {if (arr[i] < x) {if (arr[i] > minx) return false;minx = arr[i];}}return true;
}bool check() {for (int i = 0; i < n; ++i) {if (!check_idx(i)) return false;}return true;
}bool first = true;int main() {ios::sync_with_stdio(false);while (cin >> n && n != 0) {
// if (first) first = false;
// else cout << "\n";arr.resize(n);while (cin >> arr[0] && arr[0] != 0) {for (int i = 1; i < n; ++i) cin >> arr[i];if (check()) cout << "Yes\n";else cout << "No\n";}cout << "\n";}return 0;
}
半年后再来写这道题,还是想到了这种方法,虽然想到了一个优化,但是最坏的复杂度仍然是O(n^2)的。而且没有用函数封装,导致代码丑了一些。
和上次一样在换行这里卡了,UVa真恶心,还卡换行。
//
// Created by Administrator on 2022/4/20.
//#include <iostream>
#include <vector>/** 当x进入B的时候,C中都是比x小的元素,A中都是比x大的元素。* 因为进入C的元素越来越大,所以比x小的还未出现的元素肯定在C里面的,而且是以倒序出现在x的后面。* 因此对于出站的每一个x,判断后面比x小的元素是不是逆序的。如果是则为真,以后访问到就不用再判断了,如果出现一个假就不可能了*/using namespace std;template<typename T>
void print(const vector<T> &arr) {for (auto &x : arr) cout << x << " ";cout << "\n";
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n, t;vector<int> arr;vector<bool> illegal;bool fail;while (cin >> n && n) {arr.resize(n);illegal.resize(n, false);while (cin >> t && t) {for (int i = 0; i < n; ++i) illegal[i] = false;arr.clear();arr.push_back(t);for (int i = 1; i < n; ++i) {cin >> t;arr.push_back(t);}//print(arr);fail = false;for (int i = 0; i < n; ++i) {if (illegal[i]) continue;t = arr[i];illegal[i] = true;for (int j = i + 1; j < n; ++j) {if (arr[j] < arr[i]) {if (arr[j] < t) {illegal[j] = true;t = arr[j];} else {fail = true;break;}}}if (fail) break;}if (fail) cout << "No\n";else cout << "Yes\n";}cout << "\n";}return 0;
}
更好的思路
看了一下书上了代码(书上的代码真的丑,写出这么晦涩的代码也是很厉害的),发现是可以进行模拟的,而且复杂度是O(n)O(n)O(n),如果题目有心刁难我上面的解法可能就会TLE。
模拟的思路就是,刚开始肯定是按照从小到大的元素进栈,如果我们结果中当前元素直接是这个入栈的元素,那么再直接出栈,否则就丢在栈里。如果不是当前入栈元素,那么就和栈顶的元素比较,如果也不是,那就先入栈,看看后面的元素还有没有希望,如果所有元素都已经入栈了,那就没希望了,直接GG。
AC代码
#include <iostream>
#include <vector>
#include <deque>using namespace std;int n;
deque<int> s;
vector<int> arr;bool check() {int x = 1;for (int i = 0; i < n; ++i) {if (arr[i] == x) {++x;continue;}if (!s.empty()) {if (s.back() == arr[i]) {s.pop_back();continue;} else if (s.back() > arr[i]) {return false;}}
// if (x > arr[i]) return false;if (x < n) {s.push_back(x++);--i;} else {return false;}}return true;
}int main() {ios::sync_with_stdio(false);while (cin >> n && n != 0) {arr.resize(n);while (cin >> arr[0] && arr[0] != 0) {s.clear();for (int i = 1; i < n; ++i) cin >> arr[i];if (check()) cout << "Yes\n";else cout << "No\n";}cout << "\n";}
}
感觉这道题的数据很弱,我刚才把s.clear()
写到循环外面去了都AC了。。
添加了一个优化语句:当栈顶元素比结果中的当前元素大时直接不可达,原因是后面的元素肯定都比栈顶元素大。