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

相关文章

Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)

《Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)》文章介绍了如何使用dhtmlx-gantt组件来实现公司的甘特图需求,并提供了一个简单的Vue组件示例,文章还分享了一... 目录一、首先 npm 安装插件二、创建一个vue组件三、业务页面内 引用自定义组件:四、dhtmlx

javaScript在表单提交时获取表单数据的示例代码

《javaScript在表单提交时获取表单数据的示例代码》本文介绍了五种在JavaScript中获取表单数据的方法:使用FormData对象、手动提取表单数据、使用querySelector获取单个字... 方法 1:使用 FormData 对象FormData 是一个方便的内置对象,用于获取表单中的键值

Vue ElementUI中Upload组件批量上传的实现代码

《VueElementUI中Upload组件批量上传的实现代码》ElementUI中Upload组件批量上传通过获取upload组件的DOM、文件、上传地址和数据,封装uploadFiles方法,使... ElementUI中Upload组件如何批量上传首先就是upload组件 <el-upl

Docker部署Jenkins持续集成(CI)工具的实现

《Docker部署Jenkins持续集成(CI)工具的实现》Jenkins是一个流行的开源自动化工具,广泛应用于持续集成(CI)和持续交付(CD)的环境中,本文介绍了使用Docker部署Jenkins... 目录前言一、准备工作二、设置变量和目录结构三、配置 docker 权限和网络四、启动 Jenkins

Python3脚本实现Excel与TXT的智能转换

《Python3脚本实现Excel与TXT的智能转换》在数据处理的日常工作中,我们经常需要将Excel中的结构化数据转换为其他格式,本文将使用Python3实现Excel与TXT的智能转换,需要的可以... 目录场景应用:为什么需要这种转换技术解析:代码实现详解核心代码展示改进点说明实战演练:从Excel到

如何使用CSS3实现波浪式图片墙

《如何使用CSS3实现波浪式图片墙》:本文主要介绍了如何使用CSS3的transform属性和动画技巧实现波浪式图片墙,通过设置图片的垂直偏移量,并使用动画使其周期性地改变位置,可以创建出动态且具有波浪效果的图片墙,同时,还强调了响应式设计的重要性,以确保图片墙在不同设备上都能良好显示,详细内容请阅读本文,希望能对你有所帮助...

C# string转unicode字符的实现

《C#string转unicode字符的实现》本文主要介绍了C#string转unicode字符的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录1. 获取字符串中每个字符的 Unicode 值示例代码:输出:2. 将 Unicode 值格式化

python安装whl包并解决依赖关系的实现

《python安装whl包并解决依赖关系的实现》本文主要介绍了python安装whl包并解决依赖关系的实现,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录一、什么是whl文件?二、我们为什么需要使用whl文件来安装python库?三、我们应该去哪儿下

Python脚本实现图片文件批量命名

《Python脚本实现图片文件批量命名》这篇文章主要为大家详细介绍了一个用python第三方库pillow写的批量处理图片命名的脚本,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言源码批量处理图片尺寸脚本源码GUI界面源码打包成.exe可执行文件前言本文介绍一个用python第三方库pi

Java中将异步调用转为同步的五种实现方法

《Java中将异步调用转为同步的五种实现方法》本文介绍了将异步调用转为同步阻塞模式的五种方法:wait/notify、ReentrantLock+Condition、Future、CountDownL... 目录异步与同步的核心区别方法一:使用wait/notify + synchronized代码示例关键