Description
你的任务是编写一个能处理在虚拟的化学里分子式的程序,具体地说,给定你所有原子的相对原子质量,求出所有询问的分子的相对分子质量,或者报告不存在。
数据范围:原子质量 \(\leqslant 1000\),分子式长度 \(\leqslant 80\),分子包含的原子个数 \(\leqslant 10^5\)。
Solution
这篇题解按照题面分 Part 来讲。
Part 1
如何将原子式和相对原子质量之间的关系映射出来?STL 里面有一个关联容器叫 map
,可以处理本题中原子式和相对原子质量之间的对应关系。具体地,你可以将原子式为关键字,将相对原子质量作为这个关键字的值存储,这样就建立了这么个关系。
STL 里面还有个容器叫 vector
,你可以把它看作是一个数组,但是它其实比数组还要高级,因为它的大小是动态的,而且同样也可以支持任何类型的存储。那么在这里说 vector
有什么用呢?我们在处理关系时,顺便将所有的原子式全部丢进 vector
,以方便接下来的 Part 2 中判断分子式里面是否有不存在的原子式。
具体实现还请看代码。
Part 2
这也是这道题目最核心的部分了。
首先,如果没有括号的话,由于原子式只有可能是由一个大写字母或者一个大写字母 + 一个小写字母组成,所以就可以扫一遍过去,碰到大写字母判断大写字母后面判断是否有小写字母,有的话加上去。然后判断后面是否有数字,没有数字就默认按照一个来计算,否则提取出后面的数字并将这个数字乘上该元素的相对原子质量。
有括号改怎么办?这里就用到递归的思想了。我们碰到有括号的,先把括号里面的所有部分全部提取出来,然后判断后面是否有数字,没有数字就默认按照一个来计算,否则提取出后面的数字并将这个数字乘上该部分的相对原子质量总和。然后这个部分再进行一遍递归处理直到没有括号为止。
那么这道题目就做完了。
Code
namespace Solution {
string s; int x;
map<string, int> elements;
vector<string> elements_list;
ii work(string s) {
int n = s.size(), i = 0, ans = 0;
while(i < n) {
if(s[i] == '(') {
stack<char> q;
q.push(s[i]), ++i;
string tmp = "";
while(1) {
if(s[i] == '(') q.push(s[i]);
else if(s[i] == ')') {
q.pop();
if(q.empty()) break;
}
tmp += s[i++];
}
i++;
int mul = 0;
if(!isdigit(s[i])) mul = 1;
else while(isdigit(s[i])) mul = mul * 10 + s[i] - '0', i++;
ans += work(tmp) * mul;
}
string element = "";
if(isupper(s[i])) {
element += s[i];
if(islower(s[i + 1])) i++, element += s[i];
int fl = 0;
F(int, j, 0, (int)elements_list.size() - 1) if(elements_list[j] == element) {fl = 1; break;}
if(!fl) return -1;
i++;
int mul = 0;
if(!isdigit(s[i])) mul = 1;
else while(isdigit(s[i])) mul = mul * 10 + s[i] - '0', i++;
ans += elements[element] * mul;
}
}
return ans;
}
iv Main() {
while(1) {
cin >> s;
if(s == "END_OF_FIRST_PART") break;
read(x), elements[s] = x, elements_list.push_back(s);
}
while(1) {
cin >> s;
if(s == "0") break;
int ans = work(s);
if(ans == -1) puts("UNKNOWN");
else println(ans);
}
return;
}
}