C++/PTA Easy chemistry

简介: In this question, you need to write a simple program to determine if the given chemical equation is balanced. Balanced means that the amount of elements on both sides of the “=” sign is the same.

题目要求


In this question, you need to write a simple program to determine if the given chemical equation is balanced. Balanced means that the amount of elements on both sides of the “=” sign is the same.


H 2 O + C O 2 = H 2 C O 3 H_2O+CO_2=H_2CO_3

H

2

O+CO

2

=H

2

CO

3


We guarantees that each chemical equation satisfies the basic rules.


If you don’t know the basic rules of chemical equation writing, you can refer to the following conditions:


The chemical equation contains exactly one “=” sign.

For every chemical element, the first letter of each element is uppercase, and the rest of the letters are lowercase.

The number at the end of the element represents the amount of this element needed, If there is no number, it means only one element is needed.

Every chemical object may contain several chemical elements like NaCl.

The number at the beginning of every chemical object represents the number of this object, If there is no number, it means only one object is needed.

Every chemical object will be connected by “+” sign.

Chemical reaction is considered to rearrange the atoms after they are broken up

Input

The first line contains a single integer T(1≤T≤100), indicating the number of test cases.

In the next T lines, each line contains a string S(1≤∣S∣≤100), representing a Chemical equation.

It is guaranteed that S only contains uppercase letters, lowercase letters, “=” sign and “+” sign, the sum of the amount of all elements will not exceed 2147483647.


Output

If the given chemical equation is balanced, please output “Easy!”, otherwise output “Hard!” (Without quotes).


Sample Input

3

H2O+CO2=H2CO3

2NaHCO3=Na2CO3+H2O+CO2

3Cu+8HNO3=3CuNO3+2NO+4H2O


Sample Output

Easy!

Easy!

Hard!


题目翻译

在这道题目中,你需要编写一个简单的程序来判断给定的化学方程式是否平衡。平衡指的是等号两侧所含各元素的数量相等。


例如,对于方程式 H 2 O + C O 2 = H 2 C O 3 H_2O+CO_2=H_2CO_3H

2

O+CO

2

=H

2

CO

3

,它是平衡的。


我们保证每个化学方程式都满足以下基本规则:


化学方程式中恰好有一个等号。

每个元素的第一个字母大写,其余字母小写。

元素后面的数字表示该元素需要的数量,如果没有数字,则表示只需要一个该元素。

每个化学物质可能包含多个元素,如 NaCl。

每个化学物质前面的数字表示该物质的个数,如果没有数字,则表示只需要一个该物质。

化学反应被认为是将原子打散重新组合。

输入格式:


第一行包含一个整数 T ( 1 ≤ T ≤ 100 ) (1\leq T\leq100)(1≤T≤100),表示测试用例的数量。

接下来有 T 行,每行包含一个字符串 S ( 1 ≤ ∣ S ∣ ≤ 100 ) (1\leq |S|\leq100)(1≤∣S∣≤100),表示一个化学方程式。

保证 S 只包含大写字母、小写字母、等号和加号,所有元素数量之和不会超过 2 31 − 1 2^{31}-12

31

−1。


输出格式:


对于每个测试用例,如果其对应的化学方程式平衡,则输出 “Easy!”,否则输出 “Hard!”。


输入样例:

3

H2O+CO2=H2CO3

2NaHCO3=Na2CO3+H2O+CO2

3Cu+8HNO3=3CuNO3+2NO+4H2O


输出样例:

Easy!

Easy!

Hard!


解题思路

首先从标准输入读入一个整数 T,表示有 T 个测试样例。对于每一个测试样例,从标准输入读取一个化学方程式字符串 str,并且使用isEqual 函数判断该化学方程式是否平衡。如果平衡则输出 Easy!,否则输出Hard!


isEqual 函数的实现中,假设当前处理的化学方程式为左右两边分别为 A + B → C + D 的形式,其中→表示化学反应的方向。首先将化学方程式字符串按照 + 和 ="进行划分,得到各个化合物字符串,并且将它们放入一个 vector<string> 中。

然后对于左右两边的每一个化合物字符串,调用 GetElement 函数将该化合物中各个元素出现的次数添加到map<string, int>中(也就是对于每一个元素,增加它所出现的次数,或者减少它所出现的次数)。

最后遍历 map 中所有元素,如果其中有元素的系数和非零,则说明该化学方程式不平衡,返回 false;否则返回 true。


GetElement 函数将化合物字符串按照数字和字母进行划分,得到该化合物的系数、元素名称和系数,并且根据参数 div 的值(0 或 1)将该化合物中各个元素的系数加到 map 对应元素的计数器中。

如果 div 为 0,则说明当前是对左边的化学方程式进行处理,因此应该增加元素的系数;否则 div 为 1,则说明当前是对右边的化学方程式进行处理,因此应该减少元素的系数。


代码

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
using namespace std;
map<string, int> m;
void GetElement(string str, int div) {
    string s0, s1;
    int coe = 1;
    int back = 1;
    int i = 0;
    while (i < str.size() && str[i] >= '0' && str[i] <= '9')
        s0 += str[i++];
    if (!s0.empty())
        coe = stoi(s0);
    s0.clear();
    for (; i < str.size(); i++) {
        if (str[i] >= 'A' && str[i] <= 'Z') {
            s0 += str[i];
            while (i + 1 < str.size() && str[i + 1] >= 'a' && str[i + 1] <= 'z')
                s0 += str[++i];
            int tag = 0;
            while (i + 1 < str.size() && str[i + 1] >= '0' && str[i + 1] <= '9')
                tag = 1, s1 += str[i + 1], i++;
            if (tag) back = stoi(s1), i--;
            if (div)
                m[s0] -= coe * back;
            else
                m[s0] += coe * back;
            s0.clear();
            s1.clear();
            back = 1;
        }
    }
}
bool isEqual(string str) {
    vector<string> v;
    string s0;
    for (int i = 0; i < str.size(); i++) {
        if (str[i] == '=') v.push_back("-1");
        int tag = 0;
        while (i < str.size() && str[i] != '+' && str[i] != '=') tag = 1, s0 += str[i], i++;
        if (tag) v.push_back(s0), i--;
        s0.clear();
    }
    int div = 0;
    for (int i = 0; i < v.size(); i++) {
        if (v[i] == "-1") {
            div = 1;
            continue;
        }
        GetElement(v[i], div);
    }
    for (auto it = m.begin(); it != m.end(); it++)
        if (it->second) return false;
    return true;
}
int main() {
    int T;
    string str;
    cin >> T;
    while (T--) {
        cin >> str;
        if (isEqual(str))
            cout << "Easy!" << endl;
        else
            cout << "Hard!" << endl;
        m.clear();
    }
    return 0;
}


头文件及函数

<string>用于字符串操作,例如字符串的切分和转换等。在本代码中使用了该头文件中的函数 stoi


stoi函数

stoi 函数是 string to integer 的缩写,用于将字符串转换为整数,其形式如下:


int stoi (const string& str, size_t* idx = 0, int base = 10);


参数说明:


str:需要被转换为整数的字符串。

idx:如果转换失败,则 idx 返回转换失败处的字符位置。

base:指定进制数,默认为 10 进制。

该函数返回转换后的整数。如果转换失败,会抛出一个 invalid_argument 异常。


例如,在以下代码中,首先将字符串 s 转换为整数 n1,并输出其值;接着再将非数字字符串 s2 转换为整数 n2,由于转换失败,会抛出异常并终止程序:


#include <iostream>
#include <string>
using namespace std;
int main() {
    string s = "123";
    int n1 = stoi(s);
    cout << n1 << endl;
    string s2 = "hello";
    int n2 = stoi(s2);
    return 0;
}


输出结果为:


123

terminate called after throwing an instance of 'std::invalid_argument'

 what():  stoi

Aborted (core dumped)

需要注意的是,在使用 stoi 函数时需要确保输入的字符串中只包含数字字符和正负号,否则会导致转换失败。


vector:用于实现动态数组,比传统的数组更加灵活和高效。在本代码中使用了该头文件中的 vector<string> 类型。


map:用于实现关联数组,也叫映射(Map),可以将键值与元素之间建立起映射关系。在本代码中使用了该头文件中的 map<string, int> 类型。


map string&int容器

map<string, int> 是 C++ STL (Standard Template Library) 中的一种容器类型,它实现了一种将键映射到值的关联数组数据结构,也称为关联容器(Associative Container)。其中 string 表示键的类型,int 表示值的类型。具体来说,map 对应一张表,每行由一个键和一个值组成,键是唯一的,可以用来标识某种元素,值可以是任何类型。


使用 map 容器时,需要包含头文件 map。在 map 中,各个元素按照键的大小顺序自动排序,并且支持快速查找特定键对应的值。


例如,以下代码使用 map 统计了一个字符串中各个字符的出现次数:


#include <iostream>
#include <string>
#include <map>
using namespace std;
int main() {
    string str = "hello world";
    map<char, int> char_count;
    for (auto c : str) {
        char_count[c]++;
    }
    for (auto p : char_count) {
        cout << p.first << ": " << p.second << endl;
    }
    return 0;
}


输出结果为:


: 1
d: 1
e: 1
h: 1
l: 3
o: 2
r: 1
w: 1


该程序首先使用 for 循环遍历输入的字符串 str,统计各个字符出现的次数,并存储到 char_count 容器中。接着再使用 for 循环输出 char_count 中每个键值对的信息。


需要注意的是,map 中的键必须是唯一的,如果插入具有相同键的元素,则前面的元素将被覆盖。

另外,在使用 map 时,建议使用迭代器(iterator)遍历容器中的元素,而不是使用下标操作符。因为迭代器可以保证顺序访问元素,而下标访问则不能保证元素的顺序。


总结

本文使用isEqual 函数、GetElement 函数等实现化学方程式的平衡,读者可躬身实践。

我是秋说,我们下次见。

目录
相关文章
|
C++
【PTA】L1-016 验证身份(C++)
【PTA】L1-016 验证身份(C++)
185 0
【PTA】L1-016 验证身份(C++)
|
存储 C++
【PTA】L1-039 古风排版(C++)
【PTA】L1-039 古风排版(C++)
183 1
|
Java C++
部落(pta)(并查集) Java以及C++
部落(pta)(并查集) Java以及C++
143 2
|
存储 人工智能 C++
【PTA】L1-064 估值一亿的AI核心代码(详C++)
【PTA】L1-064 估值一亿的AI核心代码(详C++)
444 1
|
存储 C++ 索引
【PTA】L1-059 敲笨钟(C++)
【PTA】L1-059 敲笨钟(C++)
170 1
|
存储 人工智能 C++
【PTA】L1-093 猜帽子游戏(C++)
【PTA】L1-093 猜帽子游戏(C++)
326 1
|
C++
【PTA】L1-046 整除光棍(C++)
【PTA】L1-046 整除光棍(C++)
255 1
|
存储 C++
【PTA】L1-043 阅览室(C++)
【PTA】L1-043 阅览室(C++)
180 1
|
存储 C++
【PTA】​L1-034 点赞(C++)
【PTA】​L1-034 点赞(C++)
123 0
|
前端开发 JavaScript 测试技术
【PTA】L1-32 Left-pad (C++)
【PTA】L1-32 Left-pad (C++)
97 0
【PTA】L1-32 Left-pad (C++)