CCF-CSP 201912-3化学方程式

本文介绍了一个用于解析和验证化学方程式的C++程序,该程序能够处理复杂的化学反应表达式,包括分子式、离子式以及化学计量数。通过读取输入的化学方程式,程序可以判断方程式是否符合质量守恒定律,即反应物和生成物的原子数量是否相等。

CCF-CSP 201912-3化学方程式

满分代码:

#include <bits/stdc++.h>
#define FOR(i,s,t) for(int i=(s);i<=(t);i++)
#define ROF(i,s,t) for(int i=(s);i>=(t);i--)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 1e3 + 6;
const ll mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int readInt(){
    int x=0;
    bool sign=false;
    char c=getchar();
    while(!isdigit(c)){
        sign=c=='-';
        c=getchar();
    }
    while(isdigit(c)){
        x=x*10+c-'0';
        c=getchar();
    }
    return sign?-x:x;
}
ll readLong(){
    ll x=0;
    bool sign=false;
    char c=getchar();
    while(!isdigit(c)){
        sign=c=='-';
        c=getchar();
    }
    while(isdigit(c)){
        x=x*10+c-'0';
        c=getchar();
    }
    return sign?-x:x;
}
string readString(){
    string s;
    char c=getchar();
    while(isspace(c)){
        c=getchar();
    }
    while(!isspace(c)){
        s+=c;
        c=getchar();
    }
    return s;
}

int n, e;
string equation;
string lstr, rstr;
vector<string> lfml, rfml;
vector<int> lnum, rnum;
map<string, int> lcnt, rcnt;
int main() {
	int T = readInt();
	while (T--){
		equation = readString();
		e = equation.find('=');
		//cout << e << endl;
		lstr = equation.substr(0, e);
		rstr = equation.substr(e + 1);		
		int fst = 0, plus = 0;
		lfml.clear();
		rfml.clear();
		lnum.clear();
		rnum.clear();
		lcnt.clear();
		rcnt.clear();
		plus = lstr.find('+');
		while (plus != -1){
			string sub = lstr.substr(0, plus);
			lfml.push_back(sub);
			lstr = lstr.substr(plus + 1);
			plus = lstr.find('+');
		}
		
		if (lstr != "") lfml.push_back(lstr);
		//for (auto sub : lfml) cout << sub << " ";
		
		plus = rstr.find('+');
		while (plus != -1){
			string sub = rstr.substr(0, plus);
			rfml.push_back(sub);
			rstr = rstr.substr(plus + 1);
			plus = rstr.find('+');
		}
		if (rstr != "") rfml.push_back(rstr);
		
		/*for (auto sub : rfml) cout << sub << " ";
		cout << endl;*/
		
		for (auto sub : lfml){
			int number = 0;
			for (auto x : sub){
				if (x >= '0' && x <= '9'){
					number = number * 10 + x - '0';
				}
				else break;
			}
			if (number == 0) number = 1;
			lnum.push_back(number);
		}
		
		for (auto sub : rfml){
			int number = 0;
			for (auto x : sub){
				if (x >= '0' && x <= '9'){
					number = number * 10 + x - '0';
				}
				else break;
			}
			if (number == 0) number = 1;
			rnum.push_back(number);
		}
		
		for (int kk = 0; kk < lfml.size(); kk++){
			int number = lnum[kk];
			string sub = lfml[kk];
			vector <string> term;
			int i = 0;
			for (i = 0; i < sub.size();i++){
				if (sub[i] >= '0' && sub[i] <= '9'){continue;}
				else break;
			}
			for (; i < sub.size(); i++){
				
				string element ="";
				element += sub[i];
				if (sub[i] == '(') {term.push_back("(");}
				else if (sub[i] >= 'A' && sub[i] <= 'Z'){
					if (sub[i + 1] >= 'a' && sub[i + 1] <= 'z'){
						element += sub[i+1];
						i++;
					}
					term.push_back(element);
				}
				else if (sub[i] == ')'){term.push_back(")");}
				else if (sub[i] >= '0' && sub[i] <= '9'){
					string mm = "";
					for (;i < sub.size();i++){
						if (sub[i] >= '0' && sub[i] <= '9'){
							mm = mm + sub[i];
						}
						else {
							break;
						}
					}
					i--;
					term.push_back(mm);
				}
			}
			stack <pair<string, int>> stk;
			vector <int> w(term.size());
			vector <int> termnum(term.size());
			for (int i = 0; i < term.size(); i++){
				auto _ = term[i];
				if (_[0] >= 'A' && _[0] <= 'Z'){
					termnum[i] = 1;
				}
			}
			for (int i = 0; i < term.size(); i++){
				auto _ = term[i];
				if (_ == "("){
					stk.push({"(", i});
				}
				else if (_ == ")"){
					w[i] = stk.top().second;
					stk.pop();
				}
			}
			
			for (int i = 0; i < term.size(); i++){
				auto _ = term[i];
				if (_[0] >= '0' && _[0] <= '9'){
					int mm = 0;
					for (int j = 0; j < _.size(); j++){
						mm = mm * 10 + (char)_[j] - '0';
					}
					if (mm == 0) mm = 1;
					if (term[i-1] == ")"){
						for (int j = w[i - 1] + 1; j < i; j++){
							if (term[j][0] >= 'A' && term[j][0] <= 'Z') termnum[j] *= mm;
						}
					}else{
						if (term[i-1][0] >= 'A' && term[i-1][0] <='Z') termnum[i-1] *= mm;
					}
				}
			}
			
			for (int i = 0; i < term.size(); i++){
				auto _ = term[i];
				if (_[0] >= 'A' && _[0] <= 'Z'){
					lcnt[_] += number * termnum[i];
				}
			}
		}
		
		for (int kk = 0; kk < rfml.size(); kk++){
			int number = rnum[kk];
			string sub = rfml[kk];
			vector <string> term;
			int i = 0;
			for (i = 0; i < sub.size();i++){
				if (sub[i] >= '0' && sub[i] <= '9'){continue;}
				else break;
			}
			for (; i < sub.size(); i++){
				
				string element ="";
				element += sub[i];
				if (sub[i] == '(') {term.push_back("(");}
				else if (sub[i] >= 'A' && sub[i] <= 'Z'){
					if (sub[i + 1] >= 'a' && sub[i + 1] <= 'z'){
						element += sub[i+1];
						i++;
					}
					term.push_back(element);
				}
				else if (sub[i] == ')'){term.push_back(")");}
				else if (sub[i] >= '0' && sub[i] <= '9'){
					string mm = "";
					for (;i < sub.size();i++){
						if (sub[i] >= '0' && sub[i] <= '9'){
							mm = mm + sub[i];
						}
						else {
							break;
						}
					}
					i--;
					term.push_back(mm);
				}
			}
			stack <pair<string, int>> stk;
			vector <int> w(term.size());
			vector <int> termnum(term.size());
			for (int i = 0; i < term.size(); i++){
				auto _ = term[i];
				if (_[0] >= 'A' && _[0] <= 'Z'){
					termnum[i] = 1;
				}
			}
			for (int i = 0; i < term.size(); i++){
				auto _ = term[i];
				if (_ == "("){
					stk.push({"(", i});
				}
				else if (_ == ")"){
					w[i] = stk.top().second;
					stk.pop();
				}
			}
			
			for (int i = 0; i < term.size(); i++){
				auto _ = term[i];
				if (_[0] >= '0' && _[0] <= '9'){
					int mm = 0;
					for (int j = 0; j < _.size(); j++){
						mm = mm * 10 + (char)_[j] - '0';
					}
					if (mm == 0) mm = 1;
					if (term[i-1] == ")"){
						for (int j = w[i - 1] + 1; j < i; j++){
							if (term[j][0] >= 'A' && term[j][0] <= 'Z') termnum[j] *= mm;
						}
					}else{
						if (term[i-1][0] >= 'A' && term[i-1][0] <='Z')termnum[i-1] *= mm;
					}
				}
			}
			
			for (int i = 0; i < term.size(); i++){
				auto _ = term[i];
				if (_[0] >= 'A' && _[0] <= 'Z'){
					rcnt[_] += number * termnum[i];
				}
			}
		}
	
		int flag = 1;
		for (auto _ : lcnt){
			string s = _.first;
			int x = rcnt[s];
			if (_.second != x){
				flag = 0;
				break;
			}
		}
		for (auto _ : rcnt){
			string s = _.first;
			int x = lcnt[s];
			if (_.second != x){
				flag = 0;
				break;
			}
		}
		if (flag == 1) puts("Y");
		else puts("N");
	}
	return 0;
}

/*
11
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+2H2PO4=6H2O+Ba2(PO4)2
3Ba(OH)2+2H2PO4=Ba2(PO4)2+6H2O
4Zn+10HNO3=4Zn(NO3)2+NH4NO3+3H2O
4Na(Au(CN)2)+4NaOH=4Au+8NaCN+2H2O+O2
Cu+As=Cs+Au


*/
### CSP CCF化学方程式配平的方法与算法实现 化学方程式配平可以通过转化为数学问题来解决,即将其视为一个齐次线性方程组求解的过程。以下是详细的描述以及其实现方式。 #### 数学建模过程 通过设定化学反应物和生成物的系数作为未知变量 \(x_1, x_2, \ldots, x_n\),可以针对每种元素建立对应的守恒关系式[^1]。这些关系式构成了一个齐次线性方程组: \[ a_{11}x_1 + a_{12}x_2 + \cdots + a_{1n}x_n = 0 \\ a_{21}x_1 + a_{22}x_2 + \cdots + a_{2n}x_n = 0 \\ \vdots \\ a_{m1}x_1 + a_{m2}x_2 + \cdots + a_{mn}x_n = 0 \] 其中,\(a_{ij}\) 表示第 \(i\) 种元素在第 \(j\) 个化合物中的原子数量。该方程组通常具有无穷多解,因此需要找到一组正整数比例的特解以满足实际需求。 #### 解决方案的核心思路 利用高斯消元法或其他数值计算方法对上述矩阵形式的方程组进行简化处理,从而获得基础解系。由于目标是最小化所有系数并保持它们为正整数,还需要对方程组的结果做进一步调整——通常是乘上某个最小公倍数使得所有的分数变为整数。 #### Python 实现代码 下面提供了一个基于 NumPy 的简单实现例子用于演示如何自动完成这一任务: ```python import numpy as np from fractions import Fraction from math import gcd from functools import reduce def lcm(a, b): return abs(a * b) // gcd(a, b) def find_lcm(lst): return reduce(lcm, lst) def balance_equation(elements_matrix): A = np.array(elements_matrix).astype(&#39;float&#39;) # Perform Gaussian elimination to row echelon form. n_rows, n_cols = A.shape for i in range(min(n_rows, n_cols)): max_row_idx = np.argmax(np.abs(A[i:, i])) + i if A[max_row_idx][i] != 0: A[[max_row_idx, i]] = A[[i, max_row_idx]] pivot_val = A[i][i] if pivot_val == 0: continue A[i] /= pivot_val for j in range(i + 1, n_rows): factor = A[j][i] A[j] -= factor * A[i] # Back substitution and normalization of coefficients into integers. solution_vector = [] free_vars_count = n_cols - min(n_rows, n_cols) base_solution = [Fraction(0)] * (min(n_rows, n_cols)) + [Fraction(1)] * free_vars_count for idx in reversed(range(len(base_solution))): if idx >= min(n_rows, n_cols): break sum_of_terms = sum(-A[idx][k]*base_solution[k] for k in range(idx+1,n_cols)) base_solution[idx]=sum_of_terms/A[idx,idx] denominators = [term.denominator for term in base_solution] common_denom = find_lcm(denominators) integer_coefficients = list(map(lambda frac: int(frac*common_denom), base_solution)) return integer_coefficients example_elements_matrix = [ [-1,-1,0,0], # Coefficients for Carbon atoms [2,1,-3,-2], # Hydrogen atoms [0,0,3,2] # Oxygen atoms ] print(balance_equation(example_elements_matrix)) ``` 此程序接受输入的是表示不同分子间特定种类原子计数差别的二维列表,并返回平衡后的化学计量数组合。 #### 结果验证 最后一步是对所得结果应用常识性的化学判断确认合理性。即使存在理论上的可行解,在某些情况下也可能因为忽略了副产物或者未考虑到复杂条件下的动态变化而显得不切实际。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值