C++配平化学方程式,附源码。配平化学方程式的C++代码实现

2023-10-29 20:30

本文主要是介绍C++配平化学方程式,附源码。配平化学方程式的C++代码实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

化学方程式是化学反应简明的表达形式,它从“质”和“量”两个方面表达了化学反应的意义。故化学方程式的书写是我们学习化学的过程中不可或缺的一个重要环节。当我们遇到简单的化学方程式例如:2H2 + O2 = 2H2O 时,配平则是毫无压力,但是若遇到类似Fe36Si5 + H3PO4 + K2CrO7 = FePO4 + SiO2 + K3PO4+ CrPO4 + H2O 这种元素种类繁多,化学计量数复杂的化学方程式,若仅依靠人力去配平可能是一件极为困难的事情。而计算机具有庞大的计算能力,故我们想到编写程序来解决复杂化学方程的配平。本程序将实现化学方程式和离子方程式的配平,并支持检测输入的方程式是否配平。

主要思路:

先做字符串处理,把每个物质的的每种原子数都找出来,

然后利用每种原子的守恒 关于系数 列出方程组 进行求解 (化合价好像不太现实,我化学不好)

先说方程的解法,

解线性方程组当然是要用高斯消元了。

/*
Chemical Equation Balancer
HiJ1m 2017.10.6
*/
#include<bits/stdc++.h>
using namespace std;
inline int gcd(int x,int y){return x%y==0?y:gcd(y,x%y);
}
inline int lcm(int x,int y){return x*y/gcd(x,y);
}
struct frac{                            //分数类 int a,b;void reduce(){int x=gcd(a,b);a/=x,b/=x;};frac operator = (int x){a=x,b=1;return *this;};frac operator = (const frac x){a=x.a,b=x.b;reduce();return *this;};frac operator + (const frac x){return (frac){b*x.a+a*x.b,b*x.b};};frac operator - (const frac x){return (frac){a*x.b-b*x.a,b*x.b};};frac operator * (const frac x){return (frac){a*x.a,b*x.b};};frac operator / (const frac x){return (frac){a*x.b,b*x.a};};bool operator < (const frac x){return a*x.b<b*x.a;};bool operator == (const frac x){return a*x.b==b*x.a;};void print(){if(b==1)printf("%d\n",a);else printf("%d/%d\n",a,b);};
};        
inline frac Abs(frac x){int p=x.a>0?x.a:-x.a,q=x.b>0?x.b:-x.b;return (frac){p,q};
}                                            
char s[55];
int fun[55][55];
int Map[27][27];                        //手动MAP 
frac M[55][55];                            //求解矩阵
frac ans[55];                            //解 
int Ans[55];                            //整数解 
int cnt,c1,c2,flag=1,N,K;                //cnt数元素,c1数反应物,c2总数 (未知数的数量) 
char mat[55][55];                        //存储物质的名称 
void print(){printf("%d %d\n",N,K);for(int i=1;i<=K;i++){for(int j=1;j<=N+1;j++)printf("%d ",M[i][j].a);printf("\n");}printf("\n");
}
inline int getint(int pos){                //读数 pos++;if(s[pos]>='a'&&s[pos]<='z')pos++;if(s[pos]<'0'||s[pos]>'9')return 1;                                //没数就是1 else {int x=0;while(s[pos]>='0'&&s[pos]<='9')x=x*10+s[pos]-'0',pos++;        //读元素后面的数字 return x;}
}
inline void scan(int l,int r){             //处理物质    c2++;for(int i=0;i<=r-l;i++)mat[c2][i]=s[l+i];        //存下元素的名字if(flag==1)c1++;                                //统计一下反应物数量int tmp=1;                                        //tmp是小括号倍数 for(int i=l;i<=r;i++){if(s[i]==')')tmp=1;                                                        if(s[i]=='('){int j=i+1;while(s[j]!=')')j++;            //找这个括号的范围 tmp=getint(j);                            //读")"右边的数字 }if(s[i]>='A'&&s[i]<='Z'){                    //发现元素 int x=s[i]-'A'+1,y=0;if(s[i+1]>='a'&&s[i]<='z')                //看一眼是一个字母的还是两个的 y=s[i+1]-'a'+1;if(!Map[x][y])Map[x][y]=++cnt;            //判重fun[Map[x][y]][c2]+=flag*getint(i)*tmp;    //把这个物质里的这种元素数量放进矩阵里,坐标(map[x][y],c2) }} 
}
inline bool Solve(){                    //解方程  (矩阵 高cnt,宽c2+1,c2+1列常数全0) ans[c2]=1;                                    //令最后一个解为1for(int i=1;i<=cnt;i++){for(int j=1;j<=c2;j++)M[i][j]=fun[i][j];}for(int i=1;i<=cnt;i++)M[i][c2].a=-M[i][c2].a;            //移到常数 //高斯消元过程 N=c2-1,K=cnt;for(int k=1;k<=N;k++){frac maxm=(frac){-1,1};int maxi;for(int i=k;i<=K;i++)if(maxm<Abs(M[i][k]))maxm=Abs(M[i][k]),maxi=i;if(maxm==(frac){0,1})return false;if(maxi!=k)for(int j=1;j<=N+1;j++){swap(M[k][j],M[maxi][j]);}frac tmp=M[k][k];for(int j=1;j<=N+1;j++)M[k][j]=M[k][j]/tmp;for(int i=k-1?1:2;i<=K;i++){if(i==k)continue;frac tmp=M[i][k];for(int j=1;j<=N+1;j++)M[i][j]=M[i][j]-tmp*M[k][j];}}return true;
}
int main()
{
//    printf("Chemical Equation Balancer\n");
//    printf("\nEnter the chemical equation:\n");scanf("%s",s);int lst=0;for(int i=1;i<strlen(s);i++){if(i==strlen(s)-1)scan(lst,i);                    if(s[i]=='+'||s[i]=='=')scan(lst,i-1),lst=i+1;     if(s[i]=='=')flag=-1;                            //等号后面的系数变负 }if(Solve())for(int i=1;i<=c2-1;i++)ans[i]=M[i][N+1];else printf("No Solution");int tmp=lcm(ans[1].b,ans[2].b);for(int i=3;i<=c2;i++)tmp=lcm(tmp,ans[i].b);for(int i=1;i<=c2;i++)Ans[i]=ans[i].a*tmp/ans[i].b;    //取分母Lcm,把分数变整数 for(int i=1;i<=c2;i++){if(Ans[i]>1)printf("%d",Ans[i]);for(int j=0;j<strlen(mat[i]);j++)printf("%c",mat[i][j]);if(i==c2)return 0;else if(i==c1)printf("=");else printf("+");}
}

另一个代码:

/* Exzh Cross Platfrom Toolkit (ECPT) Qt Version* (This file is the part of the ECPT Project)* Author: Exzh_PMGI* E-mail: realexzh@gmail.com* License: LGPL v3.0 / Exzh Commerical License* Copyright: (C) Exzh_PMGI* Qt Framework 5.10 has been tested successfully* If you want to use the code for business,* please contact me by my email.*/#include "exequationbalancer.h"#include <QDebug>int gcd(int x, int y) {return x % y == 0 ? y : gcd(y, x%y);
}int lcm(int x, int y) {return x * y / gcd(x, y);
}frac createFrac(int a, int b)
{frac tmp = { a,b };return tmp;
}frac Abs(frac x) {int p = x.a>0 ? x.a : -x.a, q = x.b>0 ? x.b : -x.b;return createFrac(p, q);
}string exEquationBalancer::getResult(string inputstr)
{strcpy(s,inputstr.c_str());int lst = 0;for (int i = 1;i<strlen(s);i++) {if (i == strlen(s) - 1)scan(lst, i);if (s[i] == '+' || s[i] == '='){scan(lst, i - 1);lst = i + 1;}if (s[i] == '=')flag = -1;                            //等号后面的系数变负}if (Solve())for (int i = 1;i <= c2 - 1;i++)ans[i] = M[i][N + 1];else output+="No Solution";int tmp = lcm(ans[1].b, ans[2].b);for (int i = 3;i <= c2;i++)tmp = lcm(tmp, ans[i].b);for (int i = 1;i <= c2;i++)Ans[i] = ans[i].a*tmp / ans[i].b;    //取分母Lcm,把分数变整数for (int i = 1;i <= c2;i++){if (Ans[i]>1) output+=to_string(Ans[i]);for (int j = 0;j<strlen(mat[i]);j++)output+=mat[i][j];if (i == c2){return output;qDebug()<<QString::fromStdString(output);}else if (i == c1) output+="=";else output+="+";}
}bool exEquationBalancer::Solve() {                    //解方程  (矩阵 高cnt,宽c2+1,c2+1列常数全0)ans[c2] = 1;                                    //令最后一个解为1for (int i = 1;i <= cnt;i++) {for (int j = 1;j <= c2;j++)M[i][j] = fun[i][j];}for (int i = 1;i <= cnt;i++)M[i][c2].a = -M[i][c2].a;            //移到常数//高斯消元过程N = c2 - 1, K = cnt;for (int k = 1;k <= N;k++) {frac maxm = createFrac(-1, 1);int maxi;for (int i = k;i <= K;i++)if (maxm<Abs(M[i][k]))maxm = Abs(M[i][k]), maxi = i;if (maxm == createFrac(0, 1))return false;if (maxi != k)for (int j = 1;j <= N + 1;j++) {swap(M[k][j], M[maxi][j]);}frac tmp = M[k][k];for (int j = 1;j <= N + 1;j++)M[k][j] = M[k][j] / tmp;for (int i = k - 1 ? 1 : 2;i <= K;i++) {if (i == k)continue;frac tmp = M[i][k];for (int j = 1;j <= N + 1;j++)M[i][j] = M[i][j] - tmp * M[k][j];}}return true;
}void exEquationBalancer::scan(int l, int r) {             //处理物质c2++;for (int i = 0;i <= r - l;i++)mat[c2][i] = s[l + i];        //存下元素的名字if (flag == 1)c1++;                                //统计一下反应物数量int tmp = 1;                                        //tmp是小括号倍数for (int i = l;i <= r;i++) {if (s[i] == ')')tmp = 1;if (s[i] == '(') {int j = i + 1;while (s[j] != ')')j++;            //找这个括号的范围tmp = getint(j);                            //读")"右边的数字}if (s[i] >= 'A'&&s[i] <= 'Z') {                    //发现元素int x = s[i] - 'A' + 1, y = 0;if (s[i + 1] >= 'a'&&s[i] <= 'z')                //看一眼是一个字母的还是两个的y = s[i + 1] - 'a' + 1;if (!Map[x][y])Map[x][y] = ++cnt;            //判重fun[Map[x][y]][c2] += flag * getint(i)*tmp;    //把这个物质里的这种元素数量放进矩阵里,坐标(map[x][y],c2)}}
}int exEquationBalancer::getint(int pos) {                //读数pos++;if (s[pos] >= 'a'&&s[pos] <= 'z')pos++;if (s[pos]<'0' || s[pos]>'9')return 1;                                //没数就是1else {int x = 0;while (s[pos] >= '0'&&s[pos] <= '9')x = x * 10 + s[pos] - '0', pos++;        //读元素后面的数字return x;}
}void exEquationBalancer::print() {output += to_string(N);output += " ";output += to_string(K);output += "\n";for (int i = 1;i <= K;i++) {for (int j = 1;j <= N + 1;j++){output += to_string(M[i][j].a);output += " ";}output += "\n";}output += "\n";
}

c++头文件

/* Exzh Cross Platfrom Toolkit (ECPT) Qt Version* (This file is the part of the ECPT Project)* Author: Exzh_PMGI* E-mail: realexzh@gmail.com* License: LGPL v3.0 / Exzh Commerical License* Copyright: (C) Exzh_PMGI* Qt Framework 5.10 has been tested successfully* If you want to use the code for business,* please contact me by my email.*/#ifndef EXEQUATIONBALANCER_H
#define EXEQUATIONBALANCER_H#include <string>
#include "../exstdc++.h"using namespace std;
static string output;
int lcm(int x, int y);
int gcd(int x, int y);struct frac {                            //分数类int a, b;void reduce() {int x = gcd(a, b);a /= x, b /= x;}frac createFrac(int a, int b){frac tmp = { a,b };return tmp;}frac operator = (int x) {a = x, b = 1;return *this;}frac operator = (const frac x) {a = x.a, b = x.b;reduce();return *this;}frac operator + (const frac x) {return createFrac(b*x.a + a * x.b, b*x.b);}frac operator - (const frac x) {return createFrac(a*x.b - b * x.a, b*x.b);}frac operator * (const frac x) {return createFrac(a*x.a, b*x.b);}frac operator / (const frac x) {return createFrac(a*x.b, b*x.a);}bool operator < (const frac x) {return a * x.b<b*x.a;}bool operator == (const frac x) {return a * x.b == b * x.a;}void print() {if (b == 1){output += to_string(a);output += "\n";}else{output += to_string(a);output += "/";output += to_string(b);}}
};frac createFrac(int a, int b);
frac Abs(frac x);class exEquationBalancer
{
public:string getResult(string inputstr);private:bool Solve();void scan(int l, int r);int getint(int pos);void print();char s[55];int fun[55][55];int Map[27][27];                        //手动MAPfrac M[55][55];                            //求解矩阵frac ans[55];                            //解int Ans[55];                            //整数解int cnt, c1, c2, flag = 1, N, K;                //cnt数元素,c1数反应物,c2总数 (未知数的数量)char mat[55][55];                        //存储物质的名称
};#endif // EXEQUATIONBALANCER_H

附录:

怎样用高斯消元 方法/步骤

下面的是咱们要求解的线性方程组,先把四个方程编上序号。

先把第一行乘以1/2,然后把第一行的相应倍数加到第二、三、四行上。

再把第二行乘以-2,接着将其相应的倍数加到第三、四行上,然后把第三行乘以-1/6。

将第三行的二倍加到第四行上,再把第四行乘以3/7。

然后往回代,就是把第四行的相应倍数加到第一、第二、第三行上;把第三行的相应倍数加到第一、第二行上。

再把第二行的相应倍数加到第一行上,最后根据得出的矩阵列出方程组,解得最后的解。

这篇关于C++配平化学方程式,附源码。配平化学方程式的C++代码实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/303163

相关文章

Java根据IP地址实现归属地获取

《Java根据IP地址实现归属地获取》Ip2region是一个离线IP地址定位库和IP定位数据管理框架,这篇文章主要为大家详细介绍了Java如何使用Ip2region实现根据IP地址获取归属地,感兴趣... 目录一、使用Ip2region离线获取1、Ip2region简介2、导包3、下编程载xdb文件4、J

PyQt5+Python-docx实现一键生成测试报告

《PyQt5+Python-docx实现一键生成测试报告》作为一名测试工程师,你是否经历过手动填写测试报告的痛苦,本文将用Python的PyQt5和python-docx库,打造一款测试报告一键生成工... 目录引言工具功能亮点工具设计思路1. 界面设计:PyQt5实现数据输入2. 文档生成:python-

Android实现一键录屏功能(附源码)

《Android实现一键录屏功能(附源码)》在Android5.0及以上版本,系统提供了MediaProjectionAPI,允许应用在用户授权下录制屏幕内容并输出到视频文件,所以本文将基于此实现一个... 目录一、项目介绍二、相关技术与原理三、系统权限与用户授权四、项目架构与流程五、环境配置与依赖六、完整

浅析如何使用xstream实现javaBean与xml互转

《浅析如何使用xstream实现javaBean与xml互转》XStream是一个用于将Java对象与XML之间进行转换的库,它非常简单易用,下面将详细介绍如何使用XStream实现JavaBean与... 目录1. 引入依赖2. 定义 JavaBean3. JavaBean 转 XML4. XML 转 J

Flutter实现文字镂空效果的详细步骤

《Flutter实现文字镂空效果的详细步骤》:本文主要介绍如何使用Flutter实现文字镂空效果,包括创建基础应用结构、实现自定义绘制器、构建UI界面以及实现颜色选择按钮等步骤,并详细解析了混合模... 目录引言实现原理开始实现步骤1:创建基础应用结构步骤2:创建主屏幕步骤3:实现自定义绘制器步骤4:构建U

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Android实现定时任务的几种方式汇总(附源码)

《Android实现定时任务的几种方式汇总(附源码)》在Android应用中,定时任务(ScheduledTask)的需求几乎无处不在:从定时刷新数据、定时备份、定时推送通知,到夜间静默下载、循环执行... 目录一、项目介绍1. 背景与意义二、相关基础知识与系统约束三、方案一:Handler.postDel

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

C#如何调用C++库

《C#如何调用C++库》:本文主要介绍C#如何调用C++库方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录方法一:使用P/Invoke1. 导出C++函数2. 定义P/Invoke签名3. 调用C++函数方法二:使用C++/CLI作为桥接1. 创建C++/CL