brief introduction
相信大家上中学时都会被化学方程式折腾得死去活来,尤其是配平,怎么也算不对数字。于是我写出了这款近200行的自动配平程序,这是不是你们黑暗化学中的一丝光亮呢?
usage
正常化学式输入,每一种物质之间空一格,反应物/生成物输入完后空一格并打一个‘-’(不带单引号)。一般情况下输入完后可以立刻出结果。需要保证系数在 [ 1 , 50 ] [1,50] [1,50] 之间。
code
#include<bits/stdc++.h>
using namespace std;
string s[20], t[20];
int l[20][25], r[20][25], mid[20][25], ans[25], suml[25], sumr[25], le[25], le2[25], suml2[25];
bool vis[25], flag;
map<string, int> fy, sc, ele;
vector<int> to[25];
int a = 1, b = 1, tot, cnt, ok, o;
void dfs2(int step) {
if(vis[step]) dfs2(step+1);
if(step == b+1) {
for(int i = 1;i <= tot;++i)
if(suml2[i]) return;
for(int i = 1;i <= a;++i) {
if(ans[i]!=1) printf("%d", ans[i]);
cout << s[i];
if(i != a) printf("+");
}
printf("==");
for(int i = 1;i <= b;++i) {
if(ans[a+i]!=1) printf("%d", ans[a+i]);
cout << t[i];
if(i != b) printf("+");
}
exit(0);
}
while(o) {
flag = false;
for(int i = 1;i <= tot;++i)
if(le2[i] == 1) {
int pos = to[i].size()-1;
while(pos>=0 && to[i][pos]>=step && vis[to[i][pos]]) --pos;
pos = to[i][pos];
int x = suml2[i]/r[pos][i];
if(vis[pos]) continue;
flag = true;
--o;
if(suml2[i]%r[pos][i] || !suml2[i]) return;
ans[a+pos] = x;
vis[pos] = true;
for(int j = 1;j <= tot;++j) {
if(r[pos][j]) suml2[j] -= r[pos][j]*x, --le2[j];
if(le2[j] == 1) ++o;
}
for(int j = 1;j <= tot;++j)
if(suml2[j] < 0) return;
}
if(!flag) break;
}
if(vis[step]) dfs2(step+1);
else {
int mn = 100;
for(int i = 1;i <= tot;++i) mn = min(mn, suml2[i]/r[step][i]);
for(int i = 1;i <= mn;++i) {
ans[a+step] = i;
bool fl = false;
for(int j = 1;j <= tot;++j) {
if(r[step][j]) {
suml2[j] -= r[step][j]*i, --le2[j];
if(le2[j]==1 && !fl) ++o, fl = true;
}
}
dfs2(step+1);
for(int j = 1;j <= tot;++j)
if(r[step][j]) {
suml2[j] += r[step][j]*i, ++le2[j];
if(le2[j]==1 && !fl) --o;
}
}
}
return;
}
void dfs(int step) {
if(step == a+1) {
for(int i = 1;i <= tot;++i) suml2[i] = 0, suml[i] = 0, sumr[i] = 0, le2[i] = le[i];
for(int i = 1;i <= b;++i) vis[i] = false;
o = ok;
for(int i = 1;i <= tot;++i)
for(int j = 1;j <= a;++j)
suml[i] += l[j][i]*ans[j], suml2[i] += l[j][i]*ans[j];
dfs2(1);
return;
}
for(int i = 1;i <= 50;++i) {
ans[step] = i;
dfs(step+1);
}
}
int main () {
while(cin >> s[a++] && s[a-1][0] != '-'); --a, --a;
while(cin >> t[b++] && t[b-1][0] != '-'); --b, --b;
for(int i = 1;i <= a;++i) {
for(int j = 0;j < s[i].size();++j) {
string str; str.clear();
if(isupper(s[i][j])) {
str += s[i][j];
if(islower(s[i][j+1])) ++j, str += s[i][j];
fy[str] = 1;
}
}
}
for(int i = 1;i <= b;++i) {
for(int j = 0;j < t[i].size();++j) {
string str; str.clear();
if(isupper(t[i][j])) {
str += t[i][j];
if(islower(t[i][j+1])) ++j, str += t[i][j];
if(fy[str] == 0) printf("Error!"), exit(0);
sc[str] = 1;
}
}
}
for(auto it = fy.begin(); it != fy.end();++it) {
ele.insert({it->first, ++tot});
if(!sc[it->first]) printf("Error!"), exit(0);
}
for(int i = 1; i <= a;++i) {
for(int j = 0;j < s[i].size();++j) {
string str; str.clear();
if(s[i][j] == '(') {
++j; cnt = 0;
while(s[i][j] != ')') {
str.clear();
str += s[i][j];
if(islower(s[i][j+1])) ++j, str += s[i][j];
++j;
int num = 1;
if(!isdigit(s[i][j])) mid[++cnt][ele[str]] = num;
else {
num = s[i][j]-'0';
if(isdigit(s[i][j+1])) ++j, num = 10*num+s[i][j]-'0';
++j; mid[++cnt][ele[str]] = num;
}
}
++j;
int num = s[i][j]-'0';
if(isdigit(s[i][j+1])) ++j, num = 10*num+s[i][j]-'0';
for(int j = 1;j <= cnt;++j)
for(int k = 1;k <= tot;++k)
l[i][k] += mid[j][k]*num;
}
else {
str += s[i][j];
if(islower(s[i][j+1])) ++j, str += s[i][j];
int num = 1;
if(!isdigit(s[i][j+1])) {l[i][ele[str]] += num; continue;}
++j, num = s[i][j]-'0';
if(!isdigit(s[i][j+1])) {l[i][ele[str]] += num; continue;}
++j, num = 10*num+s[i][j]-'0';
l[i][ele[str]] = num;
}
}
}
for(int i = 1; i <= b;++i) {
for(int j = 0;j < t[i].size();++j) {
string str; str.clear();
if(t[i][j] == '(') {
++j; cnt = 0;
while(t[i][j] != ')') {
str.clear();
str += t[i][j];
if(islower(t[i][j+1])) ++j, str += t[i][j];
++j;
int num = 1;
if(!isdigit(t[i][j])) mid[++cnt][ele[str]] = num;
else {
num = t[i][j]-'0';
if(isdigit(t[i][j+1])) ++j, num = 10*num+t[i][j]-'0';
++j; mid[++cnt][ele[str]] = num;
}
to[ele[str]].push_back(i), ++le[ele[str]];
}
++j;
int num = t[i][j]-'0';
if(isdigit(t[i][j+1])) ++j, num = 10*num+t[i][j]-'0';
for(int j = 1;j <= cnt;++j)
for(int k = 1;k <= tot;++k)
r[i][k] += mid[j][k]*num;
}
else {
str += t[i][j];
if(islower(t[i][j+1])) ++j, str += t[i][j];
to[ele[str]].push_back(i), ++le[ele[str]];
int num = 1;
if(!isdigit(t[i][j+1])) {r[i][ele[str]] += num; continue;}
++j, num = t[i][j]-'0';
if(!isdigit(t[i][j+1])) {r[i][ele[str]] += num; continue;}
++j, num = 10*num+t[i][j]-'0';
r[i][ele[str]] = num;
}
}
}
for(int i = 1;i <= tot;++i)
if(le[i] == 1) ++ok;
dfs(1);
return 0;
}
demonstration