CCF-CSP认证 201912-3 化学方程式
题意描述
给出n 个化学方程式 让我们判断化学方程式是否配平
输入输出格式
输入第一行包含一个整数n 表示方程式的数量 接下来是n 行化学方程式
数据规模
n 在[1,100] 之间
算法设计
个人认为 这应该是CSP第三题中最好读懂题意的题目了 就是给几个化学方程式 让我们去判断方程式是否配平 直接上字符串处理 但是说来容易 仔细想一想 我们需要考虑的细节还是不少的 我列出了以下需要解决的问题 以及相应的解决方案
- 如何去判断方程式是平的?
我们建立一张图 map<string,gg> gg 即是 long long 用来统计元素出现的次数 方程式等号左边出现的元素使得该元素在图中的计数++ 而右边的元素使得该计数-- 最后遍历 map 只要有元素的个数不为0 即为方程式不平 反之 方程式就是配平的 - 以什么为处理的单位?
在这里我们以一个表达式作为处理的单位 将字符串用+ 号分割 分割出来的即是表达式 这里的表达式可以是H2 H20 Cu(OH)2 我们单独编写函数来处理这样的表达式 - 数字的处理?
在处理函数中 开始必须计算整个表达式的总系数 而对于每个元素 它的个数便是总系数乘以元素后面的数字 我们单独编写函数来处理数字 而且 参数是引用类型 方便我们处理下一个表达式 - 括号的处理?
这里便体现了我们以表达式作为处理对象的好处了 比如Cu(OH)2 这里括号包裹的显然也是一个表达式 只不过这个表达式的初始系数等于原来的系数 乘以 括号后面的系数 那我们显然可以递归地调用处理表达式的函数
模拟题比较繁琐 希望读者可以耐心地在这些问题的引导下 自己独立编码实现 调试 解决bug 我在代码里添加了一定的注释 希望对实现有所帮助
c++11代码
#include <bits/stdc++.h>
using namespace std;
using gg = long long;
unordered_map<string, gg> mp;
gg computenum(const string& s,gg& start){
gg res = 0;
while(start<s.size() and isdigit(s[start])){
res = res * 10 + (s[start] - '0');
start++;
}
return (res == 0 ? 1 : res);
}
void deal(const string& s,gg e){
gg i = 0, j;
e *= computenum(s, i);
while(i < s.size()){
if(isupper(s[i])){
if(i+1 < s.size() and islower(s[i+1])){
gg k = i;
i += 2;
mp[s.substr(k, 2)] += e * computenum(s,i);
}else{
gg k = i;
i += 1;
mp[s.substr(k, 1)] += e * computenum(s, i);
}
}else{
gg left = i, right = i + 1, num = 1;
while(num!=0 and right < s.size()){
if(s[right] == '(')
num++;
else if(s[right] == ')')
num--;
right++;
}
deal(s.substr(left + 1, right - left - 2), e * computenum(s, right));
i = right;
}
}
}
void compute(const string& s,gg exp){
gg i, j;
for (i = 0; i < s.size();){
j = s.find('+', i);
if(j == string::npos){
deal(s.substr(i),exp);
i = s.size();
}else{
deal(s.substr(i, j - i),exp);
i = j + 1;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
gg ni;
cin >> ni;
string s;
while (ni--){
cin >> s;
auto j = s.find('=');
compute(s.substr(0, j), 1);
compute(s.substr(j + 1),-1);
for(auto i : mp){
if(i.second !=0){
cout << "N\n";
goto loop;
}
}
cout << "Y\n";
loop:;
mp.clear();
}
return 0;
}
|