首页 / 算法 / NOIP 双栈排序(贪心算法)
NOIP 双栈排序(贪心算法)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了NOIP 双栈排序(贪心算法),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3069字,纯文字阅读大概需要5分钟。
内容图文
![NOIP 双栈排序(贪心算法)](/upload/InfoBanner/zyjiaocheng/642/d61b57a2fe1a4ed7972bea3621f7714f.jpg)
题目描述
Tom最近在研究一个有趣的排序问题。如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序。
操作a
如果输入序列不为空,将第一个元素压入栈S1
操作b
如果栈S1不为空,将S1栈顶元素弹出至输出序列
操作c
如果输入序列不为空,将第一个元素压入栈S2
操作d
如果栈S2不为空,将S2栈顶元素弹出至输出序列
如果一个1~n的排列P可以通过一系列操作使得输出序列为1,2,…,(n-1),n,Tom就称P是一个“可双栈排序排列”。例如(1,3,2,4)就是一个“可双栈排序序列”,而(2,3,4,1)不是。下图描述了一个将(1,3,2,4)排序的操作序列:<a,c,c,b,a,d,d,b>
当然,这样的操作序列有可能有几个,对于上例(1,3,2,4),<a,c,c,b,a,d,d,b>是另外一个可行的操作序列。Tom希望知道其中字典序最小的操作序列是什么。
【输入】
输入文件twostack.in的第一行是一个整数n。
第二行有n个用空格隔开的正整数,构成一个1~n的排列。
【输出】
输出文件twostack.out共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
【输入输出样例1】
输入:
4
1 3 2 4
输出:
a b a a b b a b
思路
能弹出,则弹出,优先放在S1中(输出的方案按照字典序输出,所以优先放在S1中)
首先思考:
能放在S1中的情况:
1.S1栈顶为0,即S1没有数
2.当前输入值小于S1栈顶,而且S2栈顶没有数
肯定不能放在S1的情况:
1. 当前输入的值大于S1栈顶
特殊情况:当前输入值小于S1、S2栈顶
例如:
S1栈顶 = 10,S2栈顶= 8,现在进来一个7,看上去很难判断7到底放在哪里,如果放S1,后面来个9,再来个6,就无法放了。但是如果先来的是6,并且已经排完了1-5,那么我们可以在后续操作中把7弄走仔细想想不难发现,7不能放在S1中,当且仅当存在一个位置K,满足a[k]>7,且在k之后有位置L,满足a[L]<7也就是说(i, j, k)不能同时在栈中,当且仅当(i < j < k)且(a[k] < a[i] < a[j])
程序流程
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1001;
int N, a[MAXN], s1[MAXN], tp1, s2[MAXN], tp2; //a存放的是输入序列
vector<char> v; //定义一个v的动态数组
bool check(int pos) {
if(!tp1) return 1; // s1里面没有数值,可以存放
int i, j;
if(a[pos] > s1[tp1]) return 0; //如果输入的值大于栈S1栈顶,不能存放在S1中
if(!tp2) return 1; // 可以存放在S1栈顶中
for(i = pos + 1; i <= N; i++) if(a[i] > a[pos] && a[i] > s2[tp2]) break; //特殊情况
for(j = i + 1; j <= N; j++) if(a[j] < a[pos]) return 0;
return 1;
}
int main() {
cin>>N;
for(int i = 1; i <= N; i++) cin>>a[i];
int now = 1;
for(int i = 1; i <= N+1; i++) {
// 这个数刚好是我当前需要的数,那么输入,输出
if(a[i] == now) {now++; v.push_back('a'); v.push_back('b'); continue;}
while(now == s1[tp1] || now == s2[tp2]) {
if(now == s1[tp1]) v.push_back('b'), tp1--, now++; // 如果这个数在s1的栈顶,则输出b
if(now == s2[tp2]) v.push_back('d'), tp2--, now++; //如果这个数在s2的栈顶,则输出d
}
if(i == N + 1) break; //所有的数,都找完了跳出循环圈
if(check(i)) {v.push_back('a'); s1[++tp1] = a[i]; continue;} //放在s1里面
if(!tp2 || a[i] < s2[tp2]) {v.push_back('c'); s2[++tp2] = a[i]; continue;} //放在s2里面
cout<<0<<endl; //上述情况都不符合,表示该数找不到存放位置,输出
return 0;
}
if(tp1 || tp2) //如果S1、S2中有数,表示没有排序完,输出0
{
cout<<0<<endl;
return 0;
}
for(int i = 0; i < v.size(); i++) cout<<v[i]<<" ";
return 0;
}
sunny_9494
发布了2 篇原创文章 · 获赞 0 · 访问量 107
私信
关注
内容总结
以上是互联网集市为您收集整理的NOIP 双栈排序(贪心算法)全部内容,希望文章能够帮你解决NOIP 双栈排序(贪心算法)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。