gym102174E 只有一端开口的瓶子
E. 只有一端开口的瓶子
https://codeforces.com/gym/102174/problem/E
栈就是像 "只有一端开口的瓶子" 一样的数据结构,大家可以理解为一个头部固定的数组,无论是取出数字还是放入数字,你都只能在数组末尾那一端(称为栈顶)修改。
非常喜欢数据结构的周老师又在给新加入 ACM 俱乐部的小萌新们传授他的人生经验......
这天,周老师得到了一个乱序的全排列,其中 1⋯n共 n 个数字,每个数字都恰好只出现一次。但是周老师不喜欢无序的东西,所以他总想要把这个数列弄成一个递增的新数列。但是他现在手里恰好只有一些简单的数据结构—— k 个栈。这些栈一开始全都为空,周老师想要只通过 3 种操作,把初始的序列变成有序的新序列:
- 取出序列当前的第一个数字,插入到第 pp 个栈的顶部:push p
- 取出第 pp 个栈的顶部数字,插入到新序列的末尾位置:pop p
- 取出第 pp 个栈的顶部数字,插入到第 qq 个栈的顶部:move p q
周老师非常的睿智,他一下就想到了如果持有的栈的个数大等于数字总个数(也就是 k≥nk≥n),那么一定可以完成这项排序工作。作为本次数据结构专题讲课的作业题,周老师想考考身为小萌新的你,至少需要多少个这样的栈才能把给定的初始序列变成有序的新序列呢?换句话说,周老师想知道 k 的最小值 min{k} 是多少。
Input
第一行输入一个正整数 T (1≤T≤100),表示数据组数。接下来 TT 组数据,每组数据均满足:
- 第一行输入一个正整数 n (1≤n≤105),表示本组数据输入的全排列序列长度。
- 第二行输入 n 个由空格间隔开的正整数 p1,p2,⋯,pn,描述全排列序列 PP 的组成元素。请注意该序列是有顺序的,操作 11 只能从前往后取数字。输入保证 [1,n] 中每个正整数在 p1⋯ pn 中恰好只出现一次。
Output
对于每组数据,请输出一个正整数 kk,表示至少需要 kk 个这样的栈才能把给定的初始序列变成有序的新序列。
思路
虽然题目的描述中说 “如果持有的栈的个数大等于数字总个数(也就是 k≥nk≥n),那么一定可以完成这项排序工作”,但实际上,并不需要那么多个栈,对于任意的n,最多只需要2个栈就可以实现排序。原因不难想到,假设我们排序时需要第k个数,我们只需要不断的执行move操作,把需要取出的数的上面的数移动到另一个栈里(感觉有点类似蜘蛛纸牌?),找出我们需要的数并将他pop出栈,不断的重复这个操作就可以在仅有两个栈的情况下实现排序。
这之后问题就可以转化为“判断一组数据能否仅用一个栈实现排序”。我们可以考虑将序列尝试输入一个栈s,在输入的过程中考虑出栈顺序 1 到 n,一旦输入了第 i 个数就将他出栈,且i + 1必须在 i 出栈后才能被考虑,如果序列结束后栈为空,说明所有的元素都在输入的过程中按照 1 - n的顺序出栈,即可以完成排序。如果输入完成后栈非空,说明无法仅用一个栈完成排序
代码
1 //https://codeforces.com/gym/102174/problem/E 2 #include<bits/stdc++.h> 3 using namespace std; 4 int main() 5 { 6 ios::sync_with_stdio(false); 7 cin.tie(0); 8 int t; 9 10 11 cin >> t; 12 while (t--) 13 { 14 stack<int> s; 15 int p = 1; 16 int n; 17 int x; 18 cin >> n; 19 for (int i = 0; i < n; i++) 20 { 21 cin >> x; 22 s.push(x); 23 while (!s.empty() && s.top() == p) 24 { 25 p++; 26 s.pop(); 27 } 28 } 29 30 if (s.empty()) 31 cout << "1\n"; 32 else 33 cout << "2\n"; 34 } 35 return 0; 36 }

浙公网安备 33010602011771号