int intAtom(char a) //大写字母
{
return a - 'A';
}
int intAtom(char a,char b) //大写字母+小写字母
{
return (a - 'A' + 1) * 26 + b - 'a';
}
例如: 对于项 10A3(B2(C2D4)2E2)2,我举的这个项包含所有情况
计算过程,这个过程是递归的
ans = 10*ans1 ans1 = A3(B2(C2D4)2E2)2
ans1 = A*3 + ans2 ans2 = (B2(C2D4)2E2)2
ans2 = ans3*2 ans3 = B2(C2D4)2E2
ans3 = B*2 + ans4 ans4 = (C2D4)2E2
ans4 = ans5 * 2 +ans7 ans5 = C2D4 ans7 = E2
ans5 = C*2 + ans6 ans6 = D4
ans6 = D*4
ans7 = E*2
如果看懂了上诉解题核心,问题已经解决,以下就是展现代码能力的了,即如何将算法用程序来实现
例如
H2+O2=H2O 分割为 H2 O2 H2O
CH4+2O2=CO2+2H2O 分割为CH4 2O2 CO2 2H2O
分割符为 +、=
本题目中只有一个=,可能有多个+,并且=将化学方程式分成两部分。
写出一个方法,完成字符串分割
void split(string str,vector<string> &ans,char spacer)
//三个参数分别为 原字符串 分割后字符串集合,分割符
vector
vector
从左往右,找到第一个不是数字的位置,使用substr进行分离,然后前面的是数字字符串,后面是化学式;
对前面的数字字符串使用stoi方法转化为int
使用递归调用,具体看代码;
到达化学式 边界 或者 碰到了右括号
统计化学式的时候,我们使用 <元素,数量>,可以得知使用pair
可以使用题目例子,来自行模拟方法处理过程,如化学式A3(B2(C2D4)2E2)2
ptr为模拟指针位置,end为expr边界,传入的参数为expr长度。
vector<pair<int,int> > singleExpr(string expr,int &ptr,int end)
{
vector<pair<int,int> > ans; //返回值
if(expr[ptr]=='(')
{
ptr++; //指针后移一位
ans = singleExpr(expr,ptr,end);
if(expr[ptr]==')')
//碰到右括号,处理右括号后面的数字
{
ptr++;
int num = 1;
string str="";
while(ptr < end && isNum(expr[ptr]))
{
str += expr[ptr];
ptr++;
}
if(str != "")
num = stoi(str);
for(int i=0;i<ans.size();i++)
ans[i].second = ans[i].second*num;
}
}
else if(isUpper( expr[ptr] ))
{
int atom;
if( ptr+1 < end && isLower(expr[ptr+1]) )
{
atom = intAtom(expr[ptr],expr[ptr+1]);
ptr += 2;
}
else
{
atom = intAtom(expr[ptr]);
ptr++;
}
int num = 1;
string str="";
while(ptr < end && isNum(expr[ptr]))
{
str += expr[ptr];
ptr++;
}
if(str != "")
num = stoi(str);
// 原子 数量 : atom num
pair<int,int> p;
p.first = atom;
p.second = num;
ans.push_back(p);
}
if(ptr<end && expr[ptr]!=')')
//递归暂停的条件是到达 边界 或者 碰到了右括号
{
vector<pair<int,int> > t2;
t2 = singleExpr(expr,ptr,end);
ans.insert(ans.end(),t2.begin(),t2.end());
}
return ans;
}
以下是AC代码
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 800;
int n;
/* 原子换算成int型的公式是
大写字母 char-'A'
大写字母+小写字母 (pre-'A'+1)*26 + char-'a'
*/
int resLeft[maxn];
int resRight[maxn];
bool isNum(char ch)
{
return ch >= '0' && ch <= '9';
}
bool isUpper(char ch)
{
return ch >= 'A' && ch <= 'Z';
}
bool isLower(char ch)
{
return ch >= 'a' && ch <= 'z';
}
int intAtom(char a)
{
return a - 'A';
}
int intAtom(char a,char b)
{
return (a - 'A' + 1) * 26 + b - 'a';
}
vector<string> split(string str,char spacer)
{
vector<string> v;
int pos1,pos2;
pos1=0;
pos2=str.find(spacer);
while( pos2 != string::npos )
{
v.push_back( str.substr(pos1,pos2-pos1) );
pos1 = pos2 + 1;
pos2 = str.find(spacer,pos1); // 从str的pos1位置开始搜寻spacer
}
if(pos1 != str.length()) //分割最后一个部分
v.push_back(str.substr(pos1));
return v;
}
vector<pair<int,int> > singleExpr(string expr,int &ptr,int end)
{
vector<pair<int,int> > ans; //返回值
if(expr[ptr]=='(')
{
ptr++; //指针后移一位
ans = singleExpr(expr,ptr,end);
if(expr[ptr]==')')
//碰到右括号,处理右括号后面的数字
{
ptr++;
int num = 1;
string str="";
while(ptr < end && isNum(expr[ptr]))
{
str += expr[ptr];
ptr++;
}
if(str != "")
num = stoi(str);
for(int i=0;i<ans.size();i++)
ans[i].second = ans[i].second*num;
}
}
else if(isUpper( expr[ptr] ))
{
int atom;
if( ptr+1 < end && isLower(expr[ptr+1]) )
{
atom = intAtom(expr[ptr],expr[ptr+1]);
ptr += 2;
}
else
{
atom = intAtom(expr[ptr]);
ptr++;
}
int num = 1;
string str="";
while(ptr < end && isNum(expr[ptr]))
{
str += expr[ptr];
ptr++;
}
if(str != "")
num = stoi(str);
// 原子 数量 : atom num
pair<int,int> p;
p.first = atom;
p.second = num;
ans.push_back(p);
}
if(ptr<end && expr[ptr]!=')')
//递归暂停的条件是到达 边界 或者 碰到了右括号
{
vector<pair<int,int> > t2;
t2 = singleExpr(expr,ptr,end);
ans.insert(ans.end(),t2.begin(),t2.end());
}
return ans;
}
void numPlusExpr(string expr,int res[])
{
/*
* 分离前导系数和化学式
* */
int pos=0; //化学式的开头位置
for(int i=0;i<expr.size();i++)
if(expr[i]>='0'&&expr[i]<='9')
continue;
else{
pos=i;
break;
}
int num=0;
if(pos==0)
num = 1;
else
num = stoi(expr.substr(0,pos));
string subStr = expr.substr(pos); //从pos一直到结尾
vector<pair<int,int> > v;
int ptr = 0;
v = singleExpr(subStr,ptr,subStr.length());
for(int i=0;i<v.size();i++)
{
int atom = v[i].first;
int number = num * v[i].second;
res[atom] += number;
}
}
void statAtom(vector<string> vec,int res[])
// 统计原子的数量,所有部分原子数相加之和,第二个参数为统计数组
{
for(int i=0;i<vec.size();i++)
numPlusExpr(vec[i],res);
}
bool isEqual(string expr)
{
string l,r;
vector<string> t;
t = split(expr,'=');
l = t[0]; //化学方程式左边
r = t[1]; //化学方程式右边
// 测试点编号1、2 只有大写字母和等号,先编写代码得20分
// 排个序就好,如果测试点是个狼人,弄个10^9个大写字母,排序就不管用了。
// string lt_1 = l,rt_1 = r;
// sort(lt_1.begin(),lt_1.end());
// sort(rt_1.begin(),rt_1.end());
// if(lt_1 != rt_1)
// return false;
/* 提交结果,答案错误,但竟然拿下了30分 哈哈 */
// 测试点编号3、4 加入小写字母和加号
// 拿个40分
// vector lt_2;
// vector rt_2;
// 原子可以为 大写字母 或者 大写字母小写字母
// lt_2 = toAtom(l);
// rt_2 = toAtom(r);
//
// sort(lt_2.begin(),lt_2.end());
// sort(rt_2.begin(),rt_2.end());
//
// if(lt_2 != rt_2)
// return false;
vector<string> left,right;
left = split(l,'+');
right = split(r,'+');
statAtom(left,resLeft);
statAtom(right,resRight);
for(int i=0;i<maxn;i++)
if(resLeft[i] != resRight[i])
return false;
return true;
}
int main() {
cin>>n;
for(int i=0;i<n;i++)
{
fill(resLeft,resLeft+maxn,0);
fill(resRight,resRight+maxn,0);
string expr;
cin>>expr;
isEqual(expr)?printf("Y\n"):printf("N\n");
}
return 0;
}
/*
* 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=Ba3(PO4)2+6H2O
* 3Ba(OH)2+2H3PO4=6H2O+Ba3(PO4)2
* 4Zn+10HNO3=4Zn(NO3)2+NH4NO3+3H2O
* 4Au+8NaCN+2H2O+O2=4Na(Au(CN)2)+4NaOH
* Cu+As=Cs+Au
* */