201912-3 化学方程式

题目描述
在这里插入图片描述
解题思路

/*
首先要清楚系数出现位置的三种情况:
1、整个化学式的首部
2、元素的右部
3、右括号的右部
如32Ba((OH)2(CO3)2)3(暂不考虑化学式的合法性)
我们从系数入手,在第一种情况下,该系数作用于化学式中的所有元素;在第二种情况下,该系数作用于紧接着的左边的元素;在第三种情况下,该系数作用于紧接着的左边的匹配括号里的所有元素,请通过上例理解。
为此,我们考虑使用一个数组将化学式的各部分存储起来arr,实现逻辑如下:
1、顺序遍历化学式
2、计算系数的第1种情况,也就是整个化学式的系数factor,继续遍历。
3、遇到左或右括号时,将左或右括号加入到arr中;遇到大写字母时,获取元素名称,将元素名称加入到arr中;遇到数字时,不存到arr中,根据系数的第2、3种情况相应处理(第1种情况已经在第二步处理完成)。
4、对于系数的第2种情况,此时数组arr的最后一个元素就是元素名称,系数作用于它即可;对于系数的第3种情况,从数组尾部逆序遍历,直到遇到左括号,将系数作用于这个范围中的元素,同时要将这一对匹配括号从数组中删除。
至此处理化学式的过程结束。
对于整个化学方程式,将其从等号两边分开处理。使用两个map分别记录左右两边的元素个数,再进行比较。
*/

#include<iostream>
#include<map>
#include<sstream> 
#include<string>
#include<vector>//迭代器用 
using namespace std;

struct elem{  //元素 
	string name;  //名称 
	int num;  //个数
	elem(string _name,int _num){
		name=_name;
		num=_num;
	} 
	
};

int toNumber(string str,int &pos){//从string pos处得到数字 
	int num=0;
	while(isdigit(str[pos])){//判断字符是否为数字 #include<cstdio>
		num=num*10+str[pos]-'0';//针对系数为大于一位的情况设计 
		pos++;//最后的出结果时pos指向的已经不再是数字了 
	}
	return num;
	
}

void calc(string &str,map<string,int> &mp){//计算化学式各元素的元素个数

      stringstream ss(str);// 整个输入流 将str转化为流信息 用getline()来对输入流分块处理#include<sstream>
	  string item;// 每一个小块化学式 
	  
	  while(getline(ss,item,'+')) {//获取每一个化学式,如 32Ba((OH)2(CO3)2)3 ss表示一个输入流,item 用来存储输入流中的流信息+ 所设置的截断字符 
	  	
	  	vector<elem> arr;//存储化学式的分解序列, 如 Ba、(、(、O、H、)、(、C、O、)、)
	  	int factor=1;//系数初始化为一
		int i=0;
		
		if(isdigit(item[i]))
		factor=toNumber(item,i);
		
		while(i<item.size()){//对每一个小化学式内部处理 此时i=1 只要处理了数字 i自动加一 
		   
		   if(isdigit(item[i]))
       {//处理数字 
		   int num=toNumber(item,i);
		   if(arr[arr.size()-1].name==")")
		   {
		   	    int j=arr.size()-1;
		   	    arr[j].name="*"; //将右括号标记为*,忽略它的存在 
		     	while(arr[--j].name!="("){
			    	arr[j].num*=num;
			} 
			arr[j].name="*";//左括号标记为*,忽略它的存在 
		   }
		   else{
		   	arr[arr.size()-1].num*=num;
		   }
    	}
		   else if(item[i]=='(')//处理左括号
		   {
		   	arr.push_back(elem("(",0));
		   	i++;
		   } 
		   else if(item[i]==')')
		   {
		   	arr.push_back(elem(")",0));
		   	if(!isdigit(item[i+1])) item.insert(i+1,"1"); //考虑到右括号右边可能不出现数字,补充底数1
		   	i++;
		   }
		   else if(isupper(item[i])){
		   	//得到元素名称
			   string name="";
			   name+=item[i];
			   i++;
			   if(islower(item[i])){
			   name+=item[i];
			   i++;   
			   }
		   arr.push_back(elem(name,1));//名称加入到序列中 
		
		   }		
		} 
		for(int i=0;i!=arr.size();i++)将“元素->个数”保存到map中 对mp赋值 
		{
			if(arr[i].name=="*") continue;//忽略序列中括号的存在 
			mp[arr[i].name]+=arr[i].num*factor; 
		 } 
		 
	  }
} 
bool judge(map<string,int> &left,map<string,int> &right)
{
	if(left.size()!=right.size())
	return false;
	map<string,int>::iterator it;//注意迭代器的定义方法 
	for(it=left.begin();it!=left.end();it++){
		if(right[it->first]!=it->second)
		return false;
	}
	return true;
	
}

int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		map<string,int> left,right;
		string str,lstr,rstr;
		
		cin>>str; 
		stringstream ss(str);
		getline(ss,lstr,'=');
		getline(ss,rstr);
		
		calc(lstr,left);
		calc(rstr,right);
		
		if(judge(left,right))
		cout<<"Y"<<endl;
		else
		cout<<"N"<<endl;
		
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值