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

相关文章

基于Redisson实现分布式系统下的接口限流

《基于Redisson实现分布式系统下的接口限流》在高并发场景下,接口限流是保障系统稳定性的重要手段,本文将介绍利用Redisson结合Redis实现分布式环境下的接口限流,具有一定的参考价值,感兴趣... 目录分布式限流的核心挑战基于 Redisson 的分布式限流设计思路实现步骤引入依赖定义限流注解实现

Python跨文件实例化、跨文件调用及导入库示例代码

《Python跨文件实例化、跨文件调用及导入库示例代码》在Python开发过程中,经常会遇到需要在一个工程中调用另一个工程的Python文件的情况,:本文主要介绍Python跨文件实例化、跨文件调... 目录1. 核心对比表格(完整汇总)1.1 自定义模块跨文件调用汇总表1.2 第三方库使用汇总表1.3 导

SpringBoot实现虚拟线程的方案

《SpringBoot实现虚拟线程的方案》Java19引入虚拟线程,本文就来介绍一下SpringBoot实现虚拟线程的方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录什么是虚拟线程虚拟线程和普通线程的区别SpringBoot使用虚拟线程配置@Async性能对比H

基于Python实现进阶版PDF合并/拆分工具

《基于Python实现进阶版PDF合并/拆分工具》在数字化时代,PDF文件已成为日常工作和学习中不可或缺的一部分,本文将详细介绍一款简单易用的PDF工具,帮助用户轻松完成PDF文件的合并与拆分操作... 目录工具概述环境准备界面说明合并PDF文件拆分PDF文件高级技巧常见问题完整源代码总结在数字化时代,PD

Python实现Word转PDF全攻略(从入门到实战)

《Python实现Word转PDF全攻略(从入门到实战)》在数字化办公场景中,Word文档的跨平台兼容性始终是个难题,而PDF格式凭借所见即所得的特性,已成为文档分发和归档的标准格式,下面小编就来和大... 目录一、为什么需要python处理Word转PDF?二、主流转换方案对比三、五套实战方案详解方案1:

SpringBoot集成EasyExcel实现百万级别的数据导入导出实践指南

《SpringBoot集成EasyExcel实现百万级别的数据导入导出实践指南》本文将基于开源项目springboot-easyexcel-batch进行解析与扩展,手把手教大家如何在SpringBo... 目录项目结构概览核心依赖百万级导出实战场景核心代码效果百万级导入实战场景监听器和Service(核心

C# async await 异步编程实现机制详解

《C#asyncawait异步编程实现机制详解》async/await是C#5.0引入的语法糖,它基于**状态机(StateMachine)**模式实现,将异步方法转换为编译器生成的状态机类,本... 目录一、async/await 异步编程实现机制1.1 核心概念1.2 编译器转换过程1.3 关键组件解析

基于Python Playwright进行前端性能测试的脚本实现

《基于PythonPlaywright进行前端性能测试的脚本实现》在当今Web应用开发中,性能优化是提升用户体验的关键因素之一,本文将介绍如何使用Playwright构建一个自动化性能测试工具,希望... 目录引言工具概述整体架构核心实现解析1. 浏览器初始化2. 性能数据收集3. 资源分析4. 关键性能指

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1