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