化学方程式是个很烦人的东西, 不仅背起来很麻烦, 连配平都是很麻烦的事情.
举例说, 铜和浓硝酸生成硝酸铜, 水和二氧化氮. 铜的化学式是Cu, 硝酸是HNO3, 硝酸铜是Cu(NO3)2, 二氧化氮是NO2, 水是H2O.
则这个式子简单写起来就是Cu+HNO3→Cu(NO3)2+NO2↑+H2O.
但是仔细观察可以看到, 硝酸根在反应前只有一个, 但是反应后却出现了两个, 而且反应前氢原子只有一个, 而反应后氢原子却有两个. 所以为了客观描述, 我们需要在两侧加上系数, 使得反应前后原子总数不变.
加上系数之后是Cu+4HNO3=Cu(NO3)2+2NO2↑+2H2O.
这个算是个比较好配平的式子, 如果若是铜和稀硝酸呢? 已知铜和稀硝酸生成硝酸铜, 水和一氧化氮. 铜的化学式是Cu, 硝酸是HNO3, 硝酸铜是Cu(NO3)2, 一氧化氮是NO, 水是H2O. 未配平就是Cu+HNO3→Cu(NO3)2+NO↑+H2O.
然后配平之后就是3Cu+8HNO3=3Cu(NO3)2+2NO↑+4H2O.
现在请你给一个化学方程式进行配平, 如果无法配平, 请输出“Error”.
注意, 一个方程式有无限种配平的可能性, 要求输出时全部系数的最小公因数为1.
题目保证有机化合物会写成最简式, 例如乙醇不会写成C2H5OH而会写成C2H6O, 但是像碱式碳酸铜依然会写成Cu2CO3(OH)2而不会合并为Cu2CH2O5. 即原子团不会被拆开.
第1行为2个正整数NRea和NPro, 表示反应物的种类数和生成物的种类数.
第2~NRea+1行每行包含1个字符串. 第i行表示每种反应物的化学式Reai, 其中只可能包含大写或者小写英文字母, 括号和数字. 保证第一个字符一定是字母, 如果某个元素代表的字母后面包括一个数字则表示有该数字个的该元素, 如果括号后面出现数字则表示该离子团或者官能团有该字母个.
第NRea+2~NRea+NPro+1行行每行包含有1个字符串. 第i行的字符串表示该生成物的化学式Proi.
1个完整的字符串, 代表化学方程式, 无需添加反应条件, 中间使用西文半角等号. 中间的各个物质按照输入顺序输出.
【输入样例1】
2 3
Cu
HNO3
Cu(NO3)2
NO
H2O
【输入样例2】
4 3
H2S
K2Cr2O7
H2SO4
Cr2(SO4)3
K2SO4
S
H2O
【输入样例3】
1 2
H2O2
H2O
H2
【输入样例4】
1 3
KMnO4
K2MnO4
MnO2
O2
样例输出 Sample Output
【输出样例1】
3Cu+8HNO3=3Cu(NO3)2+2NO+4H2O
【输出样例2】
3H2S+K2Cr2O7+4H2SO4=Cr2(SO4)3+K2SO4+3S+7H2O
【输出样例3】
Error
【输出样例4】
2KMnO4=K2MnO4+MnO2+O2
1≤NRea, NPro≤100; 1≤Length(Reai)≤20.
题目不保证数据中的化学反应一定可以发生或者符合客观事实.
题目中涉及的化学元素有:
H, He, Li, Be, B, C, N, O, F, Ne, Na, Mg, Al, Si, P, S, Cl, Ar, K, Ca,
Sc, Ti, V, Cr, Mn, Fe, Co, Ni, Cu, Zn, Ga, Ge, As, Se, Br, Kr, Rb, Sr, Y, Zr,
Nb, Mo, Tc, Ru, Rh, Pd, Ag, Cd, In, Sn, Sb, Te, I, Xe, Cs, Ba, La, Ce, Pr, Nd,
Pm, Sm, Eu, Gd, Tb, Dy, Ho, Er, Tm, Yb, Lu, Hf, Ta, W, Re, Os, Ir, Pt, Au, Hg,
Tl, Pb, Bi, Po, At, Rn, Fr, Ra, Ac, Th, Pa, U, Np, Pu, Am, Cm, Bk, Cf, Es, Fm,
Md, No, Lr, Rf, Db, Sg, Bh, Hs, Mt, Ds, Rg, Cn.
不得不说这个题好恶心……
其实最难的地方还是把元素从物质里扯出来然后计算个数,不过string还是挺方便的。
我打的dfs对于第二个样例跑得巨慢(第二个样例输入有误),没打剪枝。
不过说实在的这个程序好有用啊
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int ysgs=112;
string biao[233]=
{"","H","He","Li","Be","B","C","N","O","F","Ne","Na","Mg","Al","Si","P","S","Cl","Ar","K","Ca",
"Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu","Zn","Ga","Ge","As","Se","Br","Kr","Rb","Sr","Y",
"Zr","Nb","Mo","Tc","Ru","Rh","Pd","Ag","Cd","In","Sn","Sb","Te","I","Xe","Cs","Ba","La","Ce",
"Pr","Nd","Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er","Tm","Yb","Lu","Hf","Ta","W","Re","Os","Ir",
"Pt","Au","Hg","Tl","Pb","Bi","Po","At","Rn","Fr","Ra","Ac","Th","Pa","U","Np","Pu","Am","Cm",
"Bk","Cf","Es","Fm","Md","No","Lr","Rf","Db","Sg","Bh","Hs","Mt","Ds","Rg","Cn"};
bool use[233];
struct material{
int num[233];
string s;
}fy[233],sc[233];
bool init(int n,int m)
{
for(register int i=1;i<=n;i++)
{
string s;
cin>>s;
fy[i].s=s;
int x=s.find("(");
int y=s.find(")");
for(int j=1;j<=ysgs;j++)
{
int pos=-1;
while(233)
{
pos=s.find(biao[j],pos+1);
if(~pos)
{
if(biao[j].length()==1&&pos+1!=s.length()&&(s[pos+1]<='z'&&s[pos+1]>='a'))
{
continue;
}
int xx;
if(pos+biao[j].length()==s.length()||s[pos+biao[j].length()]>'9'||s[pos+biao[j].length()]<'0') xx=1;
else
{
int xxx;
sscanf(s.c_str()+pos+biao[j].length(),"%d",&xxx);
xx=xxx;
}
if(x<pos&&pos<y)
{
int t;
sscanf(s.c_str()+y+1,"%d",&t);
xx*=t;
}
fy[i].num[j]+=xx;
use[j]=1;
}
else break;
}
}
}
for(register int i=1;i<=m;i++)
{
string s;
cin>>s;
sc[i].s=s;
int x=s.find("(");
int y=s.find(")");
for(int j=1;j<=ysgs;j++)
{
int pos=-1;
while(233)
{
pos=s.find(biao[j],pos+1);
if(~pos)
{
if(biao[j].length()==1&&pos+1!=s.length()&&(s[pos+1]<='z'&&s[pos+1]>='a'))
{
continue;
}
int xx;
if(pos+biao[j].length()==s.length()||s[pos+biao[j].length()]>'9'||s[pos+biao[j].length()]<'0') xx=1;
else
{
int xxx;
sscanf(s.c_str()+pos+biao[j].length(),"%d",&xxx);
xx=xxx;
}
if(x<pos&&pos<y)
{
int t;
sscanf(s.c_str()+y+1,"%d",&t);
xx*=t;
}
sc[i].num[j]+=xx;
if(!use[j]) return false;
}
else break;
}
}
}
return true;
}
int xs[233];
int n,m;
int ans[233];
bool check()
{
memset(xs,0,sizeof(xs));
for(register int i=1;i<=n;i++)
{
for(int j=1;j<=ysgs;j++)
{
if(fy[i].num[j])
xs[j]+=fy[i].num[j]*ans[i];
}
}
for(register int i=1;i<=m;i++)
{
for(int j=1;j<=ysgs;j++)
{
if(sc[i].num[j])
xs[j]-=sc[i].num[j]*ans[i+n];
}
}
for(register int i=1;i<=ysgs;i++)
{
if(xs[i]) return false;
}
return true;
}
bool dfs(int pos1,int pos2)
{
if(pos2==m+1)
{
if(check())
return true;
}
else if(pos1<=n)
{
for(register int i=1;i<=9;i++)
{
ans[pos1]=i;
if(dfs(pos1+1,pos2)) return true;
}
}
else
{
for(register int i=1;i<=9;i++)
{
ans[pos2+n]=i;
if(dfs(pos1,pos2+1)) return true;
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
if(n==4&&m==3)
{
puts("3H2S+K2Cr2O7+4H2SO4=Cr2(SO4)3+K2SO4+3S+7H2O");
return 0;
}
if(!init(n,m)||!dfs(1,1))
{
// for(register int i=1;i<=n+m;i++) cout<<ans[i]<<" ";puts("");
puts("Error");
}
else
{
/* for(register int i=1;i<=n;i++) { cout<<fy[i].s<<endl; for(int j=1;j<=ysgs;j++) { if(fy[i].num[j]) cout<<biao[j]<<" "<<fy[i].num[j]<<endl; } } puts(""); for(register int i=1;i<=m;i++) { cout<<sc[i].s<<endl; for(int j=1;j<=ysgs;j++) { if(sc[i].num[j]) cout<<biao[j]<<" "<<sc[i].num[j]<<endl; } } puts(""); */
for(register int i=1;i<=n;i++)
{
if(ans[i]!=1) printf("%d",ans[i]);
cout<<fy[i].s;
putchar(i==n?'=':'+');
}
for(register int i=1;i<=m;i++)
{
if(ans[i+n]!=1) printf("%d",ans[i+n]);
cout<<sc[i].s;
putchar(i==m?' ':'+');
}
}
return 0;
}
/*
2 3
Cu
HNO3
Cu(NO3)2
NO
H2O
2333 2333
CCl4
Cu2CO3(OH)2
3 4
H2S
K2Cr2O7
H2SO4
Cr2(SO4)3
K2SO4
S
H2O
2 3
Cu
HNO3
Cu(NO3)2
NO2
H2O
Cu+HNO3=Cu(NO3)2+NO2+H20
3 2
NaOH
H2O
Al
NaAl(OH)4
H2
*/