语言:C语言 由于clion会自动加上return,所以有时候可能没写……
P1449 后缀表达式
题目描述:
所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。
如:3*(5–2)+7对应的后缀表达式为:3.5.2.-*7.+@。’@’为表达式的结束符号。‘.’为操作数的结束符号。
题解如下:
//
// Created by Lee on 2022/2/1.
//main16
//
//用数组模拟栈
#include <stdio.h>
long array[10000];
int p;//栈顶指针
int temp;//存临时数
char ch;
int main(){
while((ch=getchar())!='@'){
if(ch>='0'&&ch<='9'){
temp = temp * 10 + ch -'0';
}
else if(ch=='.'){
array[p++] = temp;
temp = 0;//一定要注意归零,否则下一次temp会用这一次的继续往上加
}
else if(ch=='+'){
int a = array[p-2];
int b = array[p-1];
p -= 2;
int c = a+b;
array[p++] = c;
}
else if(ch=='-'){
int a = array[p-2];
int b = array[p-1];
p -= 2;
int c = a-b;
array[p++] = c;
}
else if(ch=='*'){
int a = array[p-2];
int b = array[p-1];
p -= 2;
int c = a*b;
array[p++] = c;
}
else if(ch=='/'){
int a = array[p-2];
int b = array[p-1];
p -= 2;
float c = a/b;
array[p++] = c;
}
}
printf("%d",array[0]);
return 0;
}
本题需要注意的地方:
1. 数字不一定只有一位。需要根据 '.' 来判断一个数字到底有几位。
2. 栈顶指针 p 其实是指向栈顶元素的再上面一位,即array[p-1]才是栈顶元素。取数的时候需要注意。
3. 除法的运算结果向下取整。这一点题目好像没表述清楚,但是自己要注意,因为我之前用float错了。
P1981 [NOIP2013 普及组] 表达式求值
题目描述:
给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。
输入格式:
一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“+”和乘法运算符“×”,且没有括号,所有参与运算的数字均为 0 到 2^{31}−1 之间的整数。
输入数据保证这一行只有 0−9、+、这 12 种字符。
输出格式:
一个整数,表示这个表达式的值。
注意:当答案长度多于 4 位时,请只输出最后 4 位,前导 0 不输出。
题解如下:
//
// Created by Lee on 2022/2/2.
//main17
//
//思路:数字进栈,加号不处理,乘号的话,取最上面的数和下一个输入的数相乘,结果进栈。最后把栈里的元素累加。
#include <stdio.h>
//怕两个大int相乘会溢出,故使用longlong的数组
long long array[100010];
char ch[100010];//专门存放符号的数组
int p;//数字数组栈顶指针
int q;//符号数组栈顶指针
long long sum;
int main(){
scanf("%lld",&array[p++]);//先读第一个数字,然后是符号数字交替
while(1){
scanf("%c",&ch[q++]);
if(ch[q-1]=='\n') break;
scanf("%lld",&array[p++]);
if(ch[q-1]=='+') {
continue;
}
else if(ch[q-1]=='*') {
array[p-2] = array[p-2] * array[p-1];
array[p-2] = array[p-2] %10000;
p--;
}
}
for(int i=0;i<p;i++){
sum += array[i];
sum %= 10000;
}
sum = sum%10000;
printf("%d",sum);
}
本题需要注意的地方:
1. 题目只要求输出最低四位,那么我们在运算的过程中就尽可能的多做取模运算,防止溢出。我之前是只在最后加起来的过程中进行了取模的运算,没有通过。我个人的猜测是,就算乘法没有溢出,但是积很大,可能加起来的时候有溢出。所以保险起见,可以每一步都取模。
2. 本题使用数组模拟堆栈,还是要熟悉栈顶指针的位置,可以自己模拟一下进栈出栈的过程。
3. 我之所以单独处理第一个输入的数字,是因为这样可以保证后面输入是符号与数字交替,且符号在前。这样可以针对符号,对符号之后的数字进行操作。比如如果输入的是乘号,我就可以将乘号前的数字与乘号后的数字乘起来。
P1044 [NOIP2003 普及组] 栈
题目描述:
现在可以进行两种操作,
- 将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的 push 操作)
- 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的 pop 操作)
使用这两种操作,由一个操作数序列就可以得到一系列的输出序列。
你的程序将对给定的 n,计算并输出由操作数序列 1,2,…,n 经过操作可能得到的输出序列的总数。
题解如下:
//
// Created by Lee on 2022/1/28.
//main15
//
#include <stdio.h>
int n;
int res[20];
int main(){
scanf("%d",&n);
res[0] = 1;
res[1] = 1;
for(int i=2;i<=n;i++){
for(int j=0;j<i;j++){
res[i] += res[j] * res[i-1-j];
}
}
printf("%d",res[n]);
return 0;
}
本题需要注意的地方:
1. 算法:本题我是使用递归的方法求卡特兰数。
2. 卡特兰数与本题的关系:
我们假设最后一个出栈的数字是x。
那么在x之前出栈的数字可以分为两类:比x大的和比x小的。
令 f[x] 代表序列1~x通过进出栈操作可以得到的序列种类的总数。
比x小的数有x-1个,比x大的数有n-x个。把它们分开考虑,分别会有f[x-1]和f[n-x]种序列数,再根据排列组合的知识,可得f[x] = f[x-1] * f[n-x] 。
另外,由于x有n个取值,所以 res = f[0]*f[n-1] + f[1]*f[n-2] + ... + f[n-1]*f[0];
(参考了大佬inexistent的题解 登录 - 洛谷)