本周重点是队列和栈的入门,队列只能从队首出队,队尾入队;而栈只能从栈顶进行入栈和出栈;
1 移动圆盘 (100分)
给出n个圆盘的半径,现在要把这些圆盘依次放在柱子上,当准备把第i个半径为ai的圆盘放置到柱子上时,如果柱子顶部的圆盘半径小于ai,那么将柱子顶部的圆盘拿出,如果顶部的盘子半径仍然小于ai,那么继续拿出,直到顶部圆盘半径大于或等于ai为止,此时才把第i个盘子放到柱子上。那么,最后从下往上输出柱子上的圆盘半径依次是什么?
输入格式:
第一行包含一个整数n(n<=100000),表示有n个圆盘要依次放到柱子上。 接下来n行,每行一个整数,表示第i个圆盘的半径ai (ai<=100000)。
输出格式:
输出多行,表示最后柱子上中的圆盘半径。
输入样例:
5
5
3
2
4
1
输出样例:
5
4
1
#include<stdio.h>
#include<stdlib.h>
int a[100007],b[100007];
int main(){
int top=0;
int n;
int i,j=1,k;
//入栈
scanf("%d",&n);
for (i=0;i<n;i++){
scanf("%d",&b[i]);
}
a[0]=b[0];
i=1;
for (j=1;j<n;j++,i++){
if (b[j]<=a[i-1]){
a[i]=b[j];continue;
}
while(b[j]>a[i-1]){
a[i-1]=0;i--;
if (i==0) break;
}
if (i==0){
a[i]=b[j];continue;
}
a[i]=b[j];
}
if (a[0]==0) printf("%d",a[0]);
for (i=0;i<n;i++){
if (a[i]==0) break;/*因为圆盘的半径不可能等于0,若等于0,则只能是被删除或不曾使用过的(其中数组为全局变量,不曾使用的初始值为0);*/
printf("%d\n",a[i]);
}
return 0;
}
2 微信号 (100分)
小明刚认识了新同学小红,他想要小红的微信号,小红不想直接告诉他,所以给了小明一串加密了的数字,并且把解密规则告诉了小明。
解密规则是:首先删除第1个数,接着把第2个数放在这串数的最后面,再删除第3个数,并把第4个数放在这串数的最后面……直至只剩最后一个数,把最后一个数也删除。
按照删除的顺序,把这些数字连在一起就是小红的微信号。请你按照解密规则帮小明得到小红的微信号。
输入格式:
第一行包括一个正整数n(1 < n < 500),表示这串微信号的长度;
第二行包括n个数字,即加密的小红的微信号。
输出格式:
输出解密后的微信号,相邻数字之间有空格。
输入样例:
9
1 2 3 4 5 6 7 8 9
输出样例:
1 3 5 7 9 4 8 6 2
#include<stdio.h>
#include<stdlib.h>
int a[5007],b[5007];
int main(){
int n;
int i,j=1,k;
scanf("%d",&n);
int head=1,rear=n;
for (i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for (head=1;head<=rear;head++){
b[j]=a[head];//数组b用来存放删除的数据
head++;
a[++rear]=a[head];//将数据移到这串数的最后面
j++;
}
for (k=1;k<=n;k++){
printf("%d ",b[k]);
}
return 0;
}
3 糖果 (100分)
学校里有n个孩子,从1到n对这些孩子进行编号。老师将给孩子们分发糖果,第i个孩子希望至少获得ai个糖果。
老师要求孩子们排队。 最初,第i个孩子站在队伍的第i个位置。 然后,老师开始分发糖果。分发糖果的规则是:将m个糖果给队伍中的第一个孩子,如果这个孩子没有得到足够的糖果,那么这个孩子会走到队伍的尽头;否则这个孩子就回家了。当队伍不为空时,重复这个规则一直分发糖果。 如果考虑所有孩子回家的顺序。老师想知道,哪个孩子将是这个顺序中的最后一个?
输入格式:
第一行包含两个整数n,m(1≤n≤100; 1≤m≤100)。 第二行包含n个整数a1,a2,...,an(1≤ai≤100)。
输出格式:
输出一个整数,代表最后一个孩子的编号。
输入样例:
在这里给出一组输入。例如:
3 3
2 4 3
输出样例:
在这里给出相应的输出。例如:
2
#include<stdio.h>
#include<stdlib.h>
int a[10000007],sum[1000007];
int main(){
int n,m;
int b[1000007];
int i,j=0,k;
scanf("%d %d",&n,&m);
for (i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for (k=1;k<=n;k++){
b[k]=k;//存放编号
}
int head=1,rear=n;
for (head=1;head<=rear;head++){
sum[head]+=m;
if (sum[head]>=a[head]){
continue;
}
b[++rear]=b[head];
a[rear]=a[head];
sum[rear]=sum[head];
}
printf("%d",b[rear]);
return 0;
}
4 谁比我大 (100分)
给定一个含有n个整数的数列a1,a2,...an。定义函数 f(ai)表示数列中第i个元素ai之后第一个大于ai的元素的下标,若这样的元素不存在,则f(ai)=0。
输入格式:
第一行包含一个正整数n(n<=1e6);
第二行包含n个正整数 a1,a2,...an(1<=ai<=1e9)。
输出格式:
输出仅一行包含 n个整数,分别代表 f(ai) 的值。
输入样例:
5
1 4 2 3 5
输出样例:
2 5 4 5 0
#include<stdio.h>
#include<stdlib.h>
int a[1000007];
int i,j,k;
int n;
int f(int m){
int temp=0;
for (k=i+1;k<=n;k++){
if (a[k]>m){
temp=k;break;
}
}
return temp;
}
int main(){
scanf("%d",&n);
for (i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for (i=1;i<=n;i++){
j=f(a[i]);
printf("%d ",j);
}
return 0;/*此题更好的做法是单调栈,我的做法暴力求解,不是太好,而且好像在洛谷一题差不多的要用单调栈才能过,但这个能过PTA*/
}
5 后缀表达式 (100分)
这题很经典,原理的话参考这篇博客 作者讲得很清楚
所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右进行(不用考虑运算符的优先级)。
如:中缀表达式 3(5–2)+7 对应的后缀表达式为:352-7+ 。
请将给出的中缀表达式转化为后缀表达式并输出。
输入格式:
输入仅一行为中缀表达式,式中所有数字均为个位数,表达式长度小于1000。
输出格式:
输出一行,为后缀表达式,式中无空格。
输入样例:
2+48+(88+1)/3
输出样例:
248+881+3/+
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#include<math.h>
#include<time.h>
#define ll long long
#define MAX 1000007
#define Max(a,b)((a)>(b)?a:b)
#define Min(a,b)((a)>(b)?b:a)
int pr(char op) {
int di;
if (op=='*'||op =='/')di=2;
if (op=='+'||op=='-')di=1;
if (op=='(')di=0;
return di;
}
char a[MAX],b[MAX];
int main(){
int i,j,k,l,m=0,n;
scanf("%s",a);
l=strlen(a);
for(i=0;i<l;i++){
if(isdigit(a[i]))printf("%c",a[i]);
else{
if(m==0)b[++m]=a[i];
else if(a[i]=='(')b[++m]=a[i];
else if(a[i]==')'){
while(b[m]!='('){
printf("%c",b[m]);
m--;
} m--;
}
else {
while(pr(a[i])<=pr(b[m])){
printf("%c",b[m]);
m--;
if(m==0)break;
}
b[++m]=a[i];
}
}
}
while(m!=0){
printf("%c",b[m]);
m--;
}
return 0;
}
6 后缀表达式计算 (100分)
这题也很经典,原理的话参考这篇博客 作者说的很清楚
类似的题目P1449 后缀表达式
Kunkun学长觉得应该让学弟学妹了解一下这个知识点:后缀表达式相对于中缀表达式更容易让计算机理解和学习。现在kunkun学长给出一串后缀表达式,你能帮他算出这个后缀表达式的值吗?
输入格式:
第一行输入后缀表达式长度n(1<=n<=25000);
第二行输入一个字符串表示后缀表达式(每个数据或者符号之间用逗号隔开,保证输入的后缀表达式合法,每个数包括中间结果保证不超过long long长整型范围)
输出格式:
输出一个整数,即后缀表达式的值。
输入样例1:
6
10,2,+
输出样例1:
12
输入样例2:
14
2,10,2,+,6,/,-
输出样例2:
0
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <stack>
using namespace std;
stack<long long> a;
long long now,real[25007];
char num[25007];
int main(){
int n;
cin>>n;
int i,j=0,flag=0;
for (i=0;i<n;i++){
cin>>num[i];
}
for (i=0;i<n;i++){
if (num[i]>='0'&&num[i]<='9'){
now*=10;now+=num[i]-'0';
}
else if((num[i]==',')){
if (num[i-1]>='0'&&num[i-1]<='9'){
if (flag==0){
real[++j]=now;
}
else {
real[++j]=now*(-1);
}
now=0;flag=0;
}
else if(num[i-1]=='+'){
real[j-1]=real[j]+real[j-1];
real[j]=0;
j--;
}
else if(num[i-1]=='-'){
real[j-1]=real[j-1]-real[j];
real[j]=0;
j--;
}
else if(num[i-1]=='*'){
real[j-1]=real[j-1]*real[j];
real[j]=0;
j--;
}
else if(num[i-1]=='/'){
real[j-1]=real[j-1]/real[j];
real[j]=0;
j--;
}
}
else {
if (i<n-1){
if(num[i]=='-'){
if (num[i+1]!=',')flag=1;
}
continue;
}
else {
if(num[i]=='+'){
real[j-1]=real[j]+real[j-1];
real[j]=0;
j--;
}
else if(num[i]=='-'){
real[j-1]=real[j-1]-real[j];
real[j]=0;
j--;
}
else if(num[i]=='*'){
real[j-1]=real[j-1]*real[j];
real[j]=0;
j--;
}
else if(num[i]=='/'){
real[j-1]=real[j-1]/real[j];
real[j]=0;
j--;
}
}
}
}
cout<<real[1]<<endl;
return 0;
}