题目描述
做化学题时,小 F 总是里算错相对分子质量,这让他非常苦恼。
小 F 找到了你,请你来帮他算一算给定物质的相对分子质量。
如果你没有学过相关内容也没有关系,你可以从样例和提示里理解该题所求内容。
输入格式
输入一行,为一个长度为 L (L≤100) 的不含空格的字符串,表示给定物质的化学式。
化学式仅包括以下内容:
- 元素:如
Au
(金),Hf
(铪),出现的所有元素及其相对原子质量以附表为准。 - 下标
_{}
:表示某个原子、离子或者原子团的个数,如H_{2}O
表示 H2O (水),C_{60}
表示 C60 (足球烯)。 - 括号
()
:表示一个原子团,下标对团内物质生效。如Ca(OH)_{2}
表示 Ca(OH)2 (熟石灰)。 - 水合物
~
:如CuSO_{4}~5H_{2}O
表示 CuSO4⋅5H2O(胆矾)。水之前如果存在数字,保证一定是大于 22 的正整数,如果省略该部分则默认为 1 。如上述胆矾中,表示水的个数的5
。
形式化地讲,你处理的化学式满足以下规则:
分子
~
数量H_{2}O
其中数量或水合部分可省。
对于分子,满足:
部分
_{
数量}
部分_{
数量}
...部分_{
数量}
其中数量可省。
对于每个“部分”(原子,原子团,离子……),满足:
元素
或
(
元素_{
数量}
元素_{
数量}
... 元素_{
数量})
其中数量可省。
请注意,满足上述条件的化学式不会出现括号嵌套;上文中出现的 “数量” 所指代的数字不超过 10000。
输出格式
输出一行,包含一个整数或者小数部分为 .5
的实数,为你的计算结果。
保证结果不超过 10000。
输入输出样例
输入 #1
Au
输出 #1
197
输入 #2
HfO_{2}
输出 #2
210.5
输入 #3
Ca(OH)_{2}
输出 #3
74
输入 #4
CuSO_{4}~5H_{2}O
输出 #4
250
输入 #5
KAl(SO_{4})_{2}~12H_{2}O
输出 #5
474
解题思路(小tips)
首先 明确题目中的要求:即在字符串的读取中处理如下几种情况
1.遇到普通元素字符时,直接利用存下的unordered_map键值映射 得到对应元素值
只要注意有些元素是双元素 但仔细观察会发现 双元素都是一个大写字母+一个小写字母 因此只要进行一次if判断即可
2.()遇见括号 就将里面的元素当作一个整体单位来计算值 并且看见这里立刻就想到用栈
3._{}遇见此字符串 则将前面的括号或元素的值取出 乘括号中的数值 再存进栈中
4.最后则是在遇到~nH_{2}O时,因为题目中明确表示最后一定是水 所以只需要读取出n的数值 直接乘以18存进栈中即可 并且因为一定出现在最后 所以计算完就直接break结束 防止再次计算到后面的H_{2}O (ps:这里需要注意 题目中写明当没有~nH_{2}O部分时 是默认n=1,最后还要再次加上18,此处容易忽略 即测试点12不通过)
AC代码展示
在这里给大家提供两种思路:
1.针对此题 无括号嵌套且无双字母元素带下标的多次计算 如无(SAu_{4})_{2}
2.可计算多重嵌套且双字母元素下标
如果觉得有用 就点赞+收藏 鼓励一下吧
本题版本
#include <iostream>
#include <stack>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl '\n'
using namespace std;
stack<double> s;
unordered_map<string,double> mp;
string str;
double temp;
void prepare(){
mp["H"]=1,mp["C"]=12,mp["N"]=14,mp["O"]=16,mp["F"]=19,mp["Na"]=23,
mp["Mg"]=24,mp["Al"]=27,mp["Si"]=28,mp["P"]=31,mp["S"]=32,mp["Cl"]=35.5,
mp["K"]=39,mp["Ca"]=40,mp["Mn"]=55,mp["Fe"]=56,mp["Cu"]=64,
mp["Zn"]=65,mp["Ag"]=108,mp["I"]=127,mp["Ba"]=137,mp["Hf"]=178.5,
mp["Pt"]=195,mp["Au"]=197,mp["Hg"]=201;
}
double check(int &i){
string s1="";
s1+=str[i];
if(isupper(str[i])&&islower(str[i+1])){
i++;
s1+=str[i];
}
//cout<<mp[s1]<<endl;
return mp[s1];
}
double check2(int &i){
int temp=0;
i+=2;
double t=s.top();
s.pop();
while(isdigit(str[i])) {
temp=temp*10+str[i]-'0';
i++;
}
return t*temp;
}
int main(){
IOS;
prepare();
cin>>str;
for(int i=0;i<str.size();i++){
temp=0;
if(isalpha(str[i])){
temp=check(i);
s.push(temp);
}
else if(str[i]=='('){
i++;
while(str[i]!=')') {
int tmp=check(i);
temp+=tmp;
if(str[i+1]=='_') {
i++;
temp-=tmp;
s.push(tmp);
temp+=check2(i);
}
i++;
}
s.push(temp);
}
else if(str[i]=='_'){
s.push(check2(i));
}
else if(str[i]=='~'){
i++;
if(!isdigit(str[i])) temp=1;
while(isdigit(str[i])) {
temp=temp*10+str[i]-'0';
i++;
}
s.push(temp*18);
break;
}
}
double sum=0;
while(!s.empty()){
sum+=s.top();
s.pop();
}
cout<<sum<<endl;
return 0;
}
高级版
#include <iostream>
#include <stack>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl '\n'
using namespace std;
stack<double> s;
unordered_map<string,double> mp;
string str;
double temp;
void prepare(){
mp["H"]=1,mp["C"]=12,mp["N"]=14,mp["O"]=16,mp["F"]=19,mp["Na"]=23,
mp["Mg"]=24,mp["Al"]=27,mp["Si"]=28,mp["P"]=31,mp["S"]=32,mp["Cl"]=35.5,
mp["K"]=39,mp["Ca"]=40,mp["Mn"]=55,mp["Fe"]=56,mp["Cu"]=64,
mp["Zn"]=65,mp["Ag"]=108,mp["I"]=127,mp["Ba"]=137,mp["Hf"]=178.5,
mp["Pt"]=195,mp["Au"]=197,mp["Hg"]=201;
}
double check(int &i){
string s1="";
s1+=str[i];
if(isupper(str[i])&&islower(str[i+1])){
i++;
s1+=str[i];
}
return mp[s1];
}
double check2(int &i){
int temp=0;
i+=2;
double t=s.top();
s.pop();
while(isdigit(str[i])) {
temp=temp*10+str[i]-'0';
i++;
}
return t*temp;
}
int main(){
IOS;
prepare();
cin>>str;
for(int i=0;i<str.size();i++){
temp=0;
if(isalpha(str[i])){
temp=check(i);
s.push(temp);
}
else if(str[i]=='_'){
s.push(check2(i));
}
else if(str[i]=='('){
s.push(-1);
}
else if(str[i]==')'){
double sum=0;
while(s.top()!=-1){
sum+=s.top();
s.pop();
}
s.pop();
s.push(sum);
}
else if(str[i]=='~'){
i++;
if(!isdigit(str[i])) temp=1;
while(isdigit(str[i])) {
temp=temp*10+str[i]-'0';
i++;
}
s.push(temp*18);
break;
}
}
double sum=0;
while(!s.empty()){
sum+=s.top();
s.pop();
}
cout<<sum<<endl;
return 0;
}