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。

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/123031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件测试---等价类划分(功能测试)

能对穷举场景设计测试点-----等价类划分 等价类划分 说明&#xff1a;在所有测试数据中&#xff0c;具有某种共同特征的数据集合进行划分分类&#xff1a; 1&#xff09;有效等价类 2&#xff09;无效等价类步骤&#xff1a;1&#xff09;明确需求 2&#xff09;确定有效和无…

C语言实现输入一个字符串,递归将其逆序输出

完整代码&#xff1a; // 输入一个字符串&#xff0c;递归将其逆序输出。如输入 LIGHT&#xff0c;则输出 THGIL #include<stdio.h> #include<stdlib.h> //字符串的最大长度 #define N 20//逆序输出字符串 void func(char *str){if (*str\0){//结尾时直接退出递归…

基于MATLAB的电流、电压互感器特性的仿真分析

摘 要 电压互感器和电流互感器是电力系统中进行电能计量和继电保护的基本测量和继电保护等设备之一&#xff0c;其准确度及可靠性与电力系统的安全、可靠、经济运行密切相关。随着电力系统在监测、控制及保护等方面自动化和智能化要求的不断提高&#xff0c;传统的电磁式电压互…

[EFI]asus strix b760-i 13900F电脑 Hackintosh 黑苹果efi引导文件

硬件型号驱动情况主板 asus strix b760-i 处理器 I9 13900F 已驱动内存crucial ddr5-5200 64gb(32gb*2)(overclock 5600)已驱动硬盘 WD black sn850 500g*2 已驱动显卡rx570已驱动声卡Realtek ALCS1220A已驱动网卡Intel I225-V 2.5 Gigabit Ethernet已驱动无线网卡蓝牙Fevi T91…

Babylonjs学习笔记(六)——贴图的使用

书接上回&#xff0c;这里讨论贴图的运用&#xff01;&#xff01;&#xff01; // 创建球网格const ball MeshBuilder.CreateSphere(ball,{diameter:1},scene)ball.position new Vector3(0,1,0)// 创建PRB材质const ballMat new PBRMaterial(pbr,scene)// albedoTexture 反…

SHCTF 山河CTF Reverse方向[Week1]全WP 详解

文章目录 [WEEK1]ez_asm[WEEK1]easy_re[WEEK1]seed[WEEK1]signin[WEEK1]easy_math[WEEK1]ez_apk [WEEK1]ez_asm 从上往下读&#xff0c;第一处是xor 1Eh&#xff0c;第二处是sub 0Ah&#xff1b;逆向一下先加0A后异或1E 写个EXP data "nhuo[M7mc7uhc$7midgbTf7$7%#ubf7 …

多线程---单例模式

文章目录 什么是单例模式&#xff1f;饿汉模式懒汉模式版本一&#xff1a;最简单的懒汉模式版本二&#xff1a;考虑懒汉模式存在的线程安全问题版本三&#xff1a;更完善的解决线程安全问题版本四&#xff1a;解决指令重排序问题 什么是单例模式&#xff1f; 单例模式&#xf…

Nginx快速部署SSL证书_2023年10月29日可用

一、目的 Nginx快速部署SSL证书--2023年10月29日可用二、环境 Centos/Ubuntu服务器 前端代码文件夹&#xff1a; 假设为&#xff1a;/root/demo文件夹 域名 假设为&#xff1a;demo.com SSL证书&#xff08;通过上一篇博客获取&#xff0c;获取其他方式获取到的SSL证书&…

modelsim仿真报错:vlog-2388 ‘scl‘ already declared in this scope

问题背景&#xff1a; 1、使用vivado直接仿真的时候没有报错。 2、在vivado中调用modelsim的时候报错。 报错的代码&#xff1a; module iic_write(input clk,input rst,output scl,input en,inout sda);reg scl&#xff1b;……报错的意思是scl已经声明过了&#xff0c;mode…

保姆级教学安装Linux操作系统,以及Linux的语法入门

&#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Linux》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一定基础的程序员&#xff0c;这个专…

芯片设计中RTL级别总结

目录 一、简介二、详细介绍2.1 RTL级的基本要素和设计步骤2.2 书中推荐的设计步骤2.3 常用RTL级建模 三、其他相关链接芯片行业常用英文术语详细总结 一、简介 芯片设计级别简介 行为级&#xff08;Behavior Level&#xff09;&#xff1a;通过行为级算法描述数字系统。 寄存器…

附录B 其他第三方软件移植(FTP、OpenSSH、GDB)

目录 开发板 FTP 服务器移植与搭建vsftpd 源码下载vsftpd 移植vsftpd 服务器测试配置vsftpd添加新用户Filezilla 连接测试 开发板 OpenSSH 移植与使用OpenSSH 简介OpenSSH 移植OpenSSH 源码获取移植zlib 库移植openssl 库移植openssh 库 openssh 设置openssh 使用ssh 登录scp 命…

Java SE 学习笔记(十七)—— 单元测试、反射

目录 1 单元测试1.1 单元测试概述1.2 单元测试快速入门1.3 JUnit 常用注解 2 反射2.1 反射概述2.2 获取类对象2.3 获取构造器对象2.4 获取成员变量对象2.5 获取常用方法对象2.6 反射的作用2.6.1 绕过编译阶段为集合添加数据2.6.2 通用框架的底层原理 1 单元测试 1.1 单元测试概…

简单而高效:使用PHP爬虫从网易音乐获取音频的方法

概述 网易音乐是一个流行的在线音乐平台&#xff0c;提供了海量的音乐资源和服务。如果你想从网易音乐下载音频文件&#xff0c;你可能会遇到一些困难&#xff0c;因为网易音乐对其音频资源进行了加密和防盗链的处理。本文将介绍一种使用PHP爬虫从网易音乐获取音频的方法&…

AI诈骗防范:技术检测工具的发展与应用

在当前信息时代&#xff0c;人工智能技术的飞速发展给我们带来了许多便捷&#xff0c;但也伴随着新的威胁&#xff0c;其中之一就是AI诈骗。不法分子越来越巧妙地使用AI生成虚假信息和声音&#xff0c;因此&#xff0c;我们迫切需要发展技术检测工具来应对这一挑战。 AI诈骗的…

【python笔记】小甲鱼

P3 查看内置函数 dir(__builtins__) P4 变量名命名规则&#xff1a; 1、变量名不能以数字打头&#xff1b; 2、变量名可以是中文 字符串可以是&#xff1a; 1、单引号&#xff1a;文本中存在双引号时使用单引号 2、双引号&#xff1a;文本中存在单引号时使用双引号 当…

raft和zab算法的区别

首先&#xff0c;二者都是通过选举一个 Leader 来简化复杂度&#xff0c;后续的工作都是由 Leader 来做。 投票的时候&#xff0c;二者都需要定义一个轮次 Raft 定义了 term 来表示选举轮次 ZooKeeper 定义了 electionEpoch 来表示 同步数据的时候&#xff0c;都希望选举出来…

【Kubernetes】Operator开发之kubebuilder实战(二)

1 解决&#xff08;一&#xff09;中的资源删除问题 在Operator开发之kubebuilder实战&#xff08;一&#xff09;的最后提到了Demo和Pod删除的问题&#xff1a; 由于DemoController只监听了Demo资源的变化&#xff0c;因此&#xff0c;删除Pod时&#xff0c;DemoController不…

Linux创建逻辑卷并扩容(超详细)

目录 ​编辑 一、概念解析 1、LV逻辑卷 2、PV物理卷 3、VG卷组 二、扩容前准备 三、创建逻辑卷并扩容 1、打开虚拟机 2、进入root用户 3、查看新加入的硬盘 4、创建主分区 5、创建物理卷 6、打包为一个卷组 7、创建逻辑卷 8、格式化逻辑卷 9、挂载逻辑卷--开机自…

Go学习第十四章——Gin请求与响应

Go web框架——Gin请求与响应 1 响应1.1 String1.2 JSON&#xff08;*&#xff09;1.3 HTML&#xff08;*&#xff09;1.4 XML1.5 文件&#xff08;*&#xff09; 2 请求2.1 请求参数查询参数 (Query)动态参数 (Param)表单参数 (PostForm)原始参数 (GetRawData) 2.2 请求头2.3 …