【XJOI】题解 表达式求值-逆波兰算法+字符串处理

XJOI 9552 矩阵游戏C++题解 小明最近沉迷于一个矩阵游戏,游戏规则是:给定一个数字矩阵。该矩阵行和列相同,对于第i行,你需要将第i行的最小值(若出现相同的,选择列号较小的)和第i列的最大值(若出现相同的,选择行号较小的)交换,然后将第i行的数从小到大排序。要求输出最后的矩阵。第1行为一个整数n(不超过100),表示矩阵的行列数。接下来n行,每行n个整数。 阅读详情

题目链接

 

数学表达式求值:输入由数字、‘+’,‘—’,‘*’,‘/’,乘方’^’,小括号组成的字符串,输出运算结果;

 

输入格式:

一个数学表达式

 

输出格式:

运算结果,保留三位小数

 

样例输入:

样例输入一:
3*(5+3^2*(3-4)+6/2)+2.5
样例输入二:
2^0.5

 

样例输出:

样例输出一:
-0.500
样例输出二:
1.414

 

数据范围:

不会出现形如2^3^4的数据
运算的中间值不会很大
长度小于等于100

 

时间限制:

1s

 

空间限制:

64M

 

------------------------------------------------------------------------题解分割线----------------------------------------------------------------------------------

乍一看,这是一道很简单的模拟题,但当开始编码处理时就会发现,这是一道非常考验人细节处理(恶心人)的好题(毒瘤题)

那么这道题怎么做呢,初始的表达式用计算机来处理求值很显然是很困难的

那有什么好办法呢? 当然有啦,用逆波兰算法来求出表达式的后缀表达式,就可以有顺序的处理数值啦

先介绍一下逆波兰算法:(摘自网友博客)

 

逆波兰算法介绍

假定给定一个只 包含 加、减、乘、除,和括号的算术表达式,你怎么编写程序计算出其结果。

问题是:在表达式中,括号,以及括号的多层嵌套 的使用,运算符的优先级不同等因素,使得一个算术表达式在计算时,运算顺序往往因表达式的内容而定,不具规律性。 这样很难编写出统一的计算指令。
使用逆波兰算法可以轻松解决。他的核心思想是将普通的中缀表达式转换为后缀表达式。

转换为后缀表达式的好处是:
1、去除原来表达式中的括号,因为括号只指示运算顺序,不是完成计算必须的元素。
2、使得运算顺序有规律可寻,计算机能编写出代码完成计算。虽然后缀表达式不利于人阅读,但利于计算机处理。

 

算术表达式的组成部分

一个表达式有如下及部分元素组成

  • 操作数:可以是任何数值:1,89 , 3.14159 ...
  • 运算符:

    分为单目运算符 如 sin , cos , 双目运算符 如 加、减、乘、除 。

    运算符还会分为左结合性和右结合性。同级的左结合性的运算符从左往右依次计算。同级的右结合性的运算符从右往左依次计算。 
    如: 7-6+1 等价于 (7-6) + 1 ,因为普通加减运算符是左结合性的。
    如:C语言中的组合赋值语句: a = b = 1 等价于 a = (b=1) ,因为赋值运算符在C中是右结合性的。

    对于单目运算符,还分为前缀运算符和后缀运算符,如 sin(x) 是前缀运算符,而 阶乘运算符 : n ! 就是后缀运算符。

 

  • 分界符:一般是圆括号 ( ) , 用于指示运算的先后顺序。

在本文中,只会考虑算术表达式 有 加、减、乘、除 运算符, 左右圆括号 ( , ) ,合法的数字简单的情况。对于更加复杂的运算符,只要对这个算法轻微修改,就可以支持。

 

逆波兰算法的原理

逆波兰算法的核心步骤就2个:
1、将中缀表达式转换为后缀表达式,例如输入的原始表达式是 3*(5+7) ,转换得到 3 5 7 + *
2、根据后缀表达式,按照特定的计算规则得到最终结算结果

下面详细介绍这个2步的操作。

中缀表达式转换为后缀表达式
你需要设定一个栈SOP,和一个线性表 L 。SOP用于临时存储运算符和分界符( ,L用于存储后缀表达式。
遍历原始表达式中的每一个表达式元素
(1)如果是操作数,则直接追加到 L中。只有 运算符 或者 分界符( 才可以存放到 栈SOP中
(2)如果是分界符
         Ⅰ 如果是左括号 ( , 则 直接压入SOP,等待下一个最近的 右括号 与之配对。
          Ⅱ 如果是右括号),则说明有一对括号已经配对(在表达式输入无误的情况下)。不将它压栈,丢弃它,然后从SOP中出栈,得到元素e,将e依次追加到L里。一直循环,直到出栈元素e 是 左括号 ( ,同样丢弃他。
(3)如果是运算符(用op1表示)
        Ⅰ如果SOP栈顶元素(用op2表示) 不是运算符,则二者没有可比性,则直接将此运算符op1压栈。 例如栈顶是左括号 ( ,或者栈为空。
         Ⅱ 如果SOP栈顶元素(用op2表示) 是运算符 ,则比较op1和 op2的优先级。如果op1 > op2 ,则直接将此运算符op1压栈。
如果不满足op1 > op2,则将op2出栈,并追加到L,重复步骤3。
也就是说,如果在SOP栈中,有2个相邻的元素都是运算符,则他们必须满足:下层运算符的优先级一定小于上层元素的优先级,才能相邻。

最后,如果SOP中还有元素,则依次弹出追加到L后,就得到了后缀表达式。

 

根据后缀表达式计算得到最终结果

 

执行这步操作时,也需要一个栈scalc,用于存放计算中的操作数。

 

示例图

 

如此我们就可以将一个人类读得懂机器读不懂的算术表达式转换为有顺序的规则严谨的机器操作步骤

那么这道题就解决了

PS.这道题需要耐心的慢慢打,千万别求快,中间的小错误是很难发现的,尽量一次打好,不然调试过程会让你很难过

------------------------------------------------------------------------AC代码分割线------------------------------------------------------------------------------

AC代码:

#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define double long double
using namespace std;

int flag = 0;
string s;
stack <double> q;
stack <char> sop;
queue <char> calc;

int main ()
{
	cin >> s;
	s += '$';
	int len = s.length();
	q.push(0);
	for (int i = 0; i < len + 1; ++i)
	{
		if (s[i] >= '0' && s[i] <= '9')
		{
			double x = s[i] - '0';
			int now = i + 1;
			for (; s[now] >= '0' && s[now] <= '9' && now <= len - 1 ;)
				x = x * 10 + (s[now] - '0'), ++now;
			if (s[now] == '.')
			{
				++now;
				int cnt = 1;
				for (; s[now] >= '0' && s[now] <= '9' && now <= len - 1;)
					x = x + (double)(s[now] - '0') / (double)pow (10, cnt), ++now, ++cnt;
			}
			i = now - 1;
			q.push(x);
			continue;
		}
		else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '^')
		{
			int num, numm;
			if (s[i] == '+' || s[i] == '-')
				num = 1;
			else if (s[i] == '*' || s[i] == '/')
				num = 2;
			else if (s[i] == '^')
				num = 3;
			if (sop.empty())
				sop.push(s[i]);
			else if (sop.top() == '(')
				sop.push(s[i]);
			else
			{
				char x = sop.top();
				if (x == '+' || x == '-')
					numm = 1;
				else if (x == '*' || x == '/')
					numm = 2;
				else if (x == '^')
					numm = 3;
				for (; numm >= num ;)
				{
					sop.pop();
					calc.push(x);
					if (sop.empty())
						break;
					numm = 0;
					x = sop.top();
					if (x == '+' || x == '-')
						numm = 1;
					else if (x == '*' || x == '/')
						numm = 2;
					else if (x == '^')
						numm = 3;
				}
				sop.push(s[i]);
			}
		}
		else if (s[i] == '(')
			sop.push(s[i]);
		else if (s[i] == ')')
		{
			char x = sop.top();
			for (; x != '(' ;)
			{
				calc.push(x);
				sop.pop();
				x = sop.top();
			}
			sop.pop();
		}
		for (; !calc.empty() ;)
		{
			char x = calc.front();
			calc.pop();
			double a = q.top();
			q.pop();
			double b = q.top();
			q.pop();
			if (x == '+')
				q.push(a + b);
			else if (x == '-')
				q.push(b - a);
			else if (x == '*')
				q.push(a * b);
			else if (x == '/')
				q.push(b / a);
			else if (x == '^')
				q.push(pow (b, a));
		}
	}
	for (; !sop.empty() ;)
	{
		char x = sop.top();
		sop.pop();
		calc.push(x);
	}
	for (; !calc.empty() ;)
	{
		char x = calc.front();
		calc.pop();
		double a = q.top();
		q.pop();
		double b = q.top();
		q.pop();
		if (x == '+')
			q.push(a + b);
		else if (x == '-')
			q.push(b - a);
		else if (x == '*')
			q.push(a * b);
		else if (x == '/')
			q.push(b / a);
		else if (x == '^')
			q.push(pow (b, a));
	}
	printf ("%.3Lf\n", q.top());
	return 0;
}

 

xjoi C++ 一百多题 立即下载

相关推荐

数学表达式求值

带有变量的中缀表达式是常见的数学表达式。如果规定变量由长度不超过 8 个小写字母组成;end为保留字,表示程序段结束;用?表示输出指定变量的值,则可以设计出比较复杂的表达式(即一个可顺序执行语句序列)。例如,如果有如下语句段:

表达式求值(2) | c++ | 栈

带有变量的中缀表达式是常见的数学表达式。表示输出指定变量的值,则可以设计出比较复杂的表达式(即一个可顺序执行语句序列)。每个v表示一个变量,v.name是这个变量的名称,v.value是这个变量当前的值。为了简化编程实现,运算符只有+,-,*,/ ,%和^(指数运算),可以处理圆括号(),并假定输入的算术表达式正确。在表达式中,如果操作数出现负数(例如-8),则要特别注意。还是使用string,非常的方便,真的是干净又卫生啊。10加-8表示为:10+-8。10减-8表示为:10--8。

m0_70241024的博客 1500

表达式求值(采用栈实现)

利用栈实现算术表达式的求值,表达式中可包含加+、减(负) -、乘*、除/、 乘方^、括号( )运算符,操作数可以为浮点数。 可采用直接求中缀表达式的方法, 也可采用先转换成后缀表达式后再求值的方法(参看课件) 。 实现时需注意如下: ( 1)带小数点的数值生成 ( 理解整数数值的生成,小数部分的处理与之类似)。 ( 2)考虑负号的情况。负号与减号形式上一样,如何区分? • 输入的表达式串中第 1 个字符是’-’ – 可断定此’-’是负号 • 其余的’-’ – 若紧接在’(’之后的’-’可断定是负号 ( 3)负号的处理 • 方法 1:若已断定是负号,可先压入数值 0 进入操作数栈,如此,可 将负号看作减号。 • 方法 2: 若已断定是负号,则紧接其后的数字字符转换成数值后,要 将其对应的相反数(负数)压入操作数栈

XJOI_9291_Hello

题目描述: 请你自行编写程序,输出”I LOVE OI.”(不包括引号) 输入格式: 输出格式: 一行字符,为I LOVE OI. 样例输入: 样例输出: I LOVE OI. 参考代码: #include<iostream> using namespace std; int main(){ cout<<"I LOVE OI."<<endl; return 0; } 解题要点: 双引号内的内容一定要和输出格式一模一样,不要小写,不要忘记空格。 ...

JivinGong的博客 500

一生一芯预学习:从零搭建Verilator仿真环境与NVBoard实战

本文详细介绍了如何从零搭建Verilator仿真环境,并完成NVBoard实战项目,为'一生一芯'预学习提供完整指导。内容包括环境配置、工具安装、波形生成、自动化构建及可视化调试技巧,帮助初学者快速掌握数字逻辑设计与仿真验证的核心技能。

keras9composer的博客 701

rag综述——RAG技术发展流程、最新技术挑战与系统级优化

RAG技术发展综述:本文系统梳理了检索增强生成(RAG)技术的演进历程,从2017年开放域问答中的早期探索,到2020年正式提出RAG架构并与大模型深度融合,再到2025年向系统化、可信化和智能体化发展。当前RAG面临检索可靠性、系统效率和生成可信度三大核心挑战,解决方案包括领域自适应训练、强化语义编码、迭代检索策略等优化方向。未来RAG将向GraphRAG、SafeRAG等方向发展,从单纯性能优化转向构建可控、可审计的语言系统框架,成为高可靠大模型应用的基础设施。

lovehu6686的博客 1243

编程入门必作题

1.  给定等式  A B C D E     其中每个字母代表一个数字,且不同数字对应不                    D F G     同字母。编程求出这些数字并且打出这个数字的             +      D F G     算术计算竖式。             ───────                X Y Z D E   2. A、B、C、D、

liang851128的专栏 7051

【49】Camunda8-Self-Managed部署之Docker方式

围绕camunda8 self-managed,介绍了基于Docker部署相关服务的过程。

AlieNeny的博客 1682

表达式求值

表达式求值 1、掌握栈的特性,能利用栈的特性进行实际应用。 2、掌握“运算符优先法”,并能利用该算法对表达式求值。 1、求一个表达式的值:输入一个包含“+”、“-”、“*”、“/”、正整数和圆括号的合法表达式,计算该表达方式的运算结果。 2、有能力的同学可以考虑操作数为多位浮点数的情况。 3、所写源代码编程风格良好,有详细注释。 4、程序运行界面良好。  #include<io...

qq_44918132的博客 1030

高效静音黑科技 —— 单相直流无刷电机驱动器

然而,传统的BLDC电机驱动通常依赖于三相架构,电路复杂,成本高昂,且在低功率应用中显得有些“大材小用”。单相直流无刷电机驱动器作为一项高效、静音、经济的技术,正逐渐改变着各个领域的电机驱动方式。其精巧的控制策略、显著的优势以及广阔的应用前景,都预示着这项技术将在未来扮演越来越重要的角色。它相较于传统的三相驱动,显著简化了电路结构,降低了成本,尤其适用于低功率、对静音要求极高的应用场景。通过这些模块的协同工作,单相直流无刷电机驱动器能够实现对电机速度、扭矩的精确控制,并最大程度地降低噪声和振动。

wen8789的博客 1765

ArcGIS实战:地形湿度指数(TWI)计算全流程解析

本文详细解析了ArcGIS中地形湿度指数(TWI)的计算全流程,从DEM数据获取、填洼处理到水流方向与汇流累积量计算,最终实现TWI的精准计算。通过实战步骤指导,帮助读者掌握水文建模和土壤湿度预测的关键技术,适用于农业规划、生态研究等领域。

weixin_29231725的博客 869

表达式求值(+-*/^,栈)

题目 已知运算符的优先级为先算乘方(‘^’),再算乘除(‘*/‘),再算加减(‘±‘)。 输入包括一行,由数字和’()±*.^’和’sin’,’cos’组成,并以’#’结果。保证表达式合法,所有运算在double的精度范围之内。 输出一个小数,表示表达式的值。保留三位有效数字。 代码 #include <cstdio> #include <cstdlib> #include <iostream> #include <cmath> #define Init_Si

We have to be very hard to reach the top. 559

【2023校招】网易雷火_研发岗_笔试题解

几个月没写题,果然水平不在线了hh,AK更难实现喽,当天只AK了疯狂游戏; 题目描述和数据等尽量多的CV到了DEVC里,可能不够细节和准确; 下面进入正题,分享我们此次笔试的题目描述和代码设计吧~.........

米莱虾 4544

20-表达式求值

/*表题目内容:输入一个由数字、+,-,*,/ 组成的算术表达式,求其值。输入描述一个表达式,其中每个运算数为正整数输出描述计算结果,保留2位小数输入样例1+12*3-4/2输出样例35.00*/ #include <iostream> #include <cstdio> #include <stack> using namespace s...

weixin_30488085的博客 190

24、汽车黑客技术全解析:诊断代码、车库创建与系统攻防

本文深入探讨了汽车黑客技术的核心内容,包括诊断代码模式与参数ID、创建开放车库社区、汽车系统相关技术、硬件与软件工具、攻击与防御手段,以及车辆通信与网络安全。无论你是汽车安全研究人员、爱好者还是开发者,都能从中获取全面的技术解析与实践指南。

Apple的专栏 228

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

XJOI简介

在做题之前,先了解XJOI,有助于理解做题顺序等规则

rrc12345的博客 3429

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

7-9 逆波兰表达式求值(20 分)

#include&lt;iostream&gt; #include&lt;stack&gt; #include&lt;cstdio&gt; #include&lt;stdlib.h&gt; using namespace std; int main(){ stack&lt;int&gt;s; char str[100]; int a,b; while(~scanf("%s",str)){ ...

酱菜小可爱的博客 6220

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

九、表达式求值(1)

九、表达式求值(1) 文章目录九、表达式求值(1)题目描述解题思路上机代码 题目描述 背景: 我们的教材中已经介绍了表达式求值的算法,现在我们将该算法的功能进行扩展,要求可以处理的运算符包括:+、-、*、/、%(整数取余)、^(乘方)、(、)。 要求: 采用算符优先算法,计算的中间结果只保留整数。 输入: 第一行为整数N。表示下面有N个表达式 从第二行起的后面N行为N个由整数构成的表达式 输出: 共N行,每行为相应表达式的计算结果。 如果判断出表达式有错误,则输出:error. 如果在计算过程中出现除数为0

qq_42582489的博客 3524

【数据结构】表达式求值

【题目链接】   https://www.acwing.com/problem/content/description/153/ 【题目描述】   给出一个表达式,其中运算符仅包含+,-,*,/,^(加 减 乘 整除 乘方)要求求出表达式的最终值。   数据可能会出现括号情况,还有可能出现多余括号情况。   数据保证不会出现大于或等于231的答案。   数据可能会出现负数情况...

weixin_30835923的博客 428

运算表达式求值、栈

运算表达式求值、栈

chenyfan_blog 449

算式表达式

输入一个由数字、+,-,*,/ 组成的算术表达式,求其值 输入:正整数 输出:保留两位小数 example: 1+3*6-4/2 17 1+2*2*2-4*2/2*2+1 2 import java.util.Scanner; public class formulaExpress { public static void main(String[] args){

xianzhiyuxue的博客 667

XJOI一级二段题解(g++,即C++),也可视作C++算法竞赛教程

XJOI一级二段所有题目题解,包含知识点讲解,一学就会的XJOI题解。也可视作C++算法竞赛教程进行学习。

rrc12345的博客 3344

xjoi 1级22段题解

1.神奇的幻方幻方是一种很神奇的N∗N矩阵:它由数字1,2,3,⋯⋯,N×N构成,且每行、每列及两条对角线上的数字之和都相同。当N为奇数时,我们可以通过下方法构建一个幻方:首先将1写在第一行的中间。之后,按如下方式从小到大依次填写每个数KK=2,3,⋯,N×N):若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列;若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行;若(K。

delia781290的博客 926

XJOI一级三段题解(g++,即C++),也可视作C++算法竞赛教程

XJOI一级三段所有题目题解,包含知识点讲解,一学就会的XJOI题解。也可视作C++算法竞赛教程进行学习。

rrc12345的博客 4347
上一篇: 【笔记】二叉树遍历
下一篇: 【笔记】 素数筛法(朴素筛法,优化筛法,线性筛法)
El_Apocalipsis
博客等级 码龄9年 5粉丝 13原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值