CCF CSP——化学方程式(201912-3)

思路借鉴:
https://blog.csdn.net/wingrez/article/details/103551680

知识点复习
(一)getline(is,str,delim)
将输入流is中的字符读入到字符串str中,知道遇到定界字符delim、到达文件尾字符串的最大长度
delim字符将被读取(从输入流中删除),但不被存储。
若第三个参数缺省,则默认为换行符

(二)头文件sstream的应用
(三)C++ 11的简单学习
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
样例输入:

11
H2+O2=H2O
2H2+O2=2H2O
H2+Cl2=2NaCl
H2+Cl2=2HCl
CH4+2O2=CO2+2H2O
CaCl2+2AgNO3=Ca(NO3)2+2AgCl
3Ba(OH)2+2H3PO4=6H2O+Ba3(PO4)2
3Ba(OH)2+2H3PO4=Ba3(PO4)2+6H2O
4Zn+10HNO3=4Zn(NO3)2+NH4NO3+3H2O
4Au+8NaCN+2H2O+O2=4Na(Au(CN)2)+4NaOH
Cu+As=Cs+Au

样例输出:

N
Y
N
Y
Y
Y
Y
Y
Y
Y
N

C++ 代码

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cctype>
#include <map>

using namespace std;

struct Element{//各元素的信息(名称、数量)
    string name;
    int num;
    Element(string _name,int _num):name(_name),num(_num){}
};

int getNum(string s,int& index){//一个数可能由多位数字组成
    int result = 0; //index使用引用类型,在返回调用函数的时候,index的值会被改变
    while(isdigit(s[index])){
        result = result * 10 +s[index] - '0';
        index++;
    }
    return result;
}

void Calculate(string& s ,map<string,int>& mp){
    stringstream ss(s);//将字符串s作为输入流
    string item;
    while(getline(ss,item,'+')){//item为 系数+化学式
        vector<Element>arr;
        int factor = 1;//若系数为空串,则系数默认为1
        int i = 0;
        if(isdigit(item[i])){//若系数不是空串,则获取系数
            //在调用完getNum函数之后,i指向字符串item系数后边的元素
            factor = getNum(item,i);
        }
        while(i<item.size()){
            if(isupper(item[i])){//若为大写字母
                string name;
                name += item[i];//获取元素的名称
                i++;
                if(islower(item[i])){//该元素由两个字母组成
                    name += item[i];
                    i++;
                }
                arr.push_back(Element(name,1));
            }else if(isdigit(item[i])){//项后边的系数
                int behind = getNum(item,i);
                if(arr[arr.size()-1].name == ")"){//该系数位于右括号后边
                    int j = arr.size() - 1;
                    arr[j].name = "*";//将右括号标记为*
                    j--;
                    while(arr[j].name != "("){
                        arr[j].num *= behind;//更新括号内元素个数
                        j--;
                    }
                    arr[j].name = "*";//将做扩报标记为*
                }else{//系数在单个元素的后边
                    arr[arr.size()-1].num *= behind;
                }
            }else if(item[i]=='('){//处理左括号
                arr.push_back(Element("(",0));
                i++;
            }else if(item[i]==')'){//处理右括号
                arr.push_back(Element(")",0));
                //若右括号后边没有没有数字,则该系数默认为1
                //例如输入样例中的Na(Au(CN)2)
                if(!isdigit(item[i+1]) || item.size()==i+1){
                    item.insert(i+1,"1");//在右括号的后边插入1
                }
                i++;
            }
        }
        for(int i=0;i<arr.size();i++){
            if(arr[i].name == "*"){
                continue;
            }else{//将所有元素乘上最前边的系数,更新mp
                mp[arr[i].name] += arr[i].num * factor;
            }
        }
    }
}

void judge(map<string,int>& left,map<string,int>& right){
    if(left.size() != right.size()){//左右元素种类数不同,一定未配平
        cout<<"N"<<endl;
        return ;
    }
    //左右两边元素的种类数相同,比较各元素的个数
    for(map<string,int>::iterator it = left.begin();it!=left.end();it++){
        //若相同元素的个数不同
        if(it->second != right[it->first]){
            cout<<"N"<<endl;
            return ;
        }
    }
    cout<<"Y"<<endl;
}

int main(){
    int n;
    cin >> n;
    getchar();
    for(int i=0;i<n;i++){
        map<string,int>left,right;//存放等式左右两边的元素及个数
        string equation,str1,str2;
        getline(cin,equation);//输入方程式
        stringstream ss(equation);//将equation作为输入流
        getline(ss,str1,'=');//以 = 为界定符,且不包含=
        getline(ss,str2);
        Calculate(str1,left);//处理等式左边
        Calculate(str2,right);//处理等式右边
        judge(left,right);
    }
    return 0;
}

C++ 11 代码

#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <cctype>
#include <map>

using namespace std;

struct Element{
    string name;
    int num;
    Element(string _name,int _num):name(std::move(_name)),num(_num){}
};

int getNum(string s,int& index){
    int result = 0;
    while(isdigit(s[index])){
        result = result * 10 +s[index] - '0';
        index++;
    }
    return result;
}

void Calculate(string& s ,map<string,int>& mp){
    stringstream ss(s);
    string item;
    while(getline(ss,item,'+')){
        vector<Element>arr;
        int factor = 1;
        int i = 0;
        if(isdigit(item[i])){
            factor = getNum(item,i);
        }
        while(i<item.size()){
            if(isupper(item[i])){
                string name;
                name += item[i];
                i++;
                if(islower(item[i])){
                    name += item[i];
                    i++;
                }
                arr.emplace_back(name,1);
            }else if(isdigit(item[i])){
                int behind = getNum(item,i);
                if(arr[arr.size()-1].name == ")"){
                    int j = arr.size() - 1;
                    arr[j].name = "*";
                    j--;
                    while(arr[j].name != "("){
                        arr[j].num *= behind;
                        j--;
                    }
                    arr[j].name = "*";
                }else{
                    arr[arr.size()-1].num *= behind;
                }
            }else if(item[i]=='('){
                arr.emplace_back("(",0);
                i++;
            }else if(item[i]==')'){
                arr.emplace_back(")",0);
                if(!isdigit(item[i+1]) || item.size()==i+1){
                    item.insert(i+1,"1");
                }
                i++;
            }
        }
        for(auto & i : arr){
            if(i.name == "*"){
                continue;
            }else{
                mp[i.name] += i.num * factor;
            }
        }
    }
}

void judge(map<string,int>& left,map<string,int>& right){
    if(left.size() != right.size()){
        cout<<"N"<<endl;
        return ;
    }
    for(auto & it : left){
        if(it.second != right[it.first]){
            cout<<"N"<<endl;
            return ;
        }
    }
    cout<<"Y"<<endl;
}

int main(){
    int n;
    cin >> n;
    getchar();
    for(int i=0;i<n;i++){
        map<string,int>left,right;
        string equation,str1,str2;
        getline(cin,equation);
        stringstream ss(equation);
        getline(ss,str1,'=');
        getline(ss,str2);
        Calculate(str1,left);
        Calculate(str2,right);
        judge(left,right);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值