欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

201912-3 化学方程式

程序员文章站 2022-05-12 14:56:50
...

题目描述
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;
}