LevOJ P1583 Relative Molecular Mass

本文介绍了一种基于递归下降法解决化学式相对分子质量计算问题的方法,涉及元素识别、数值处理和括号结构处理的技术细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

With the given relative atomic mass, calculate the relative molecular mass.
Using simplest dot to represent middle-aligned dot in formula.

输入描述

Single group of test cases.
The first line is two integer n, m. (1 ≤ n ≤ 118, 1 ≤ m ≤ 100)
Next n lines, each line contains a string and a float number. Indicates the atom and the relative atomic mass.
Next m lines, each line contains a formula with atom given before.
Strings contain only letters, numbers, dots and parentheses ‘()’. No square brackets.

输出描述

Print m lines, each line contains an integer, which means the relative molecular mass rounded to integer.
Data promises that there will not be a result with the first decimal place being 5 before round. (Like 316.51)
No fabricate atom

样例输入

5 3

H 1.00794

C 12.0107

O 15.9994

Cu 63.546

S 32.065

CH4

CH3(CH2)4CH3

CuSO4.5H2O

样例输出

16

86

250

题解

  这题是英文题面,题目大意是,已知元素的相对原子质量,计算给定化学式的相对分子质量。 此题其实和数学表达式的解析大同小异。
  可以发现,对于一个简单的没有括号的化学式,可以从前往后依次扫描,每解析出一个化学元素,确定了它的个数,就在答案中累加它的贡献,遇到点号(如CuSO4.5H2O中的“.”),需要先解析出点号后面的数字(如果没有数字,默认该数为1),最终与后面化学式的相对分子质量相乘,累加进答案。
  如果化学式中有括号,就意味着括号里嵌套着另外一个化学式,我们可以把括号内的化学式看做一个整体,使用递归下降法解析它。这样,我们就完成了对给定化学式的相对分子质量的计算。
  在实现时要注意充分利用模块化的思想,定义多个函数,包括对化学元素的识别、对数字的识别、对括号的处理等功能函数,以达到复用代码,减少代码量的目的。实现的代码如下:

#include <iostream>
#include <string>
#include <unordered_map>
#include <cctype>

using namespace std;

typedef long long LL;

int n, m, len;
unordered_map<string, double>	hmp;
string molecular;

double calcOne(int& );

int getNum(int& st) {
	int ans = 0;
	while (st < len && isdigit(molecular[st]))
		ans = ans * 10 + molecular[st++] - '0';
	return ans;
}

double getOneAtomMass(int& st) {
	string tmp = "";
	tmp += molecular[st++];
	if (st < len && islower(molecular[st]))
		tmp += molecular[st++];
	return hmp[tmp];
}

double processParentheses(int& st) {
	double ans = 0;
	while (molecular[st] != ')') {
		++st;
		ans += calcOne(st);
	}
	++st;
	return ans;
}

double calcOne(int& st) {
	int num = 1;
	if (isdigit(molecular[st]))	num = getNum(st);
	double tot = 0;
	while (st < len && molecular[st] != '.' && molecular[st] != ')') {
		int cnt = 1;
		double am;
		if (isupper(molecular[st])) {
			am = getOneAtomMass(st);
			if (st < len && isdigit(molecular[st]))	
				cnt = getNum(st);
		} else if (molecular[st] == '(') {
			am = processParentheses(st);
			if (st < len && isdigit(molecular[st]))	
				cnt = getNum(st);
		}
		tot += cnt * am;
	}
	return num * tot;
}

void solve() {
	len = molecular.size();
	int st = 0;
	double ans = 0;
	while (st < len) {
		ans += calcOne(st);
		++st;
	}
	printf("%d\n", (int)(ans + 0.5));
}

int main() {
	cin >> n >> m;
	
	double mass;
	string atom;
	for (int i = 0; i < n; ++i) {
		cin >> atom >> mass;
		hmp[atom] = mass;
	}
	
	for (int i = 0; i < m; ++i) {
		cin >> molecular;
		solve();
	}
	
	return 0;
}

总结

  这道题还是比较有新意的,感觉需要具备一定的知识迁移能力。该题最关键的一点在于使用递归下降法处理化学式中的括号,递归下降也是数学表达式解析、编程语言语法解析、正则表达式解析的核心所在,非常适合用在对一部分具备递归结构的对象的解析上。
  这本是一道我在5月份AC的题目,这篇题解出现得有点迟,一部分说明可能不太到位,如果你看了感觉一头雾水,可以跳过文字,琢磨一下代码的逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值