题外话

说起来我作死做这题是觉得这个程序可以十块钱卖给化学组骗餐饭吃,结果发现氧化还原反应配不了,因为有什么归中不交叉率云云可以确定唯一配平系数,但是可怜的程序做不到,所以这个赚钱计划宣告破产 QAQ

解析

首先我们把每一个物质的系数看做未知数,把每一种元素看做方程,那么根据等号两边的元素系数相等可以列出方程,很显然,一个化学方程式如果要能配平,n 个元素就需要 n+1 个物质,这样才会有多组整倍数解。
然后高斯消元就可以了,最后枚举最后一个物质的系数,就可以得到所有物质的系数了。
其他的就是一些麻烦的地方,耐心点处理即可,比如提取元素,因为题目中提到的元素只会有两个字母,所以哈希很好写~括号也可以特殊处理,一口气看看括号后面的系数是多少什么的…..

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
using namespace std;
int c1,c2,n,m,bj,now;//bj: 是否有无数解的标记
double a[205][205],eps=1e-10;
char wz[205][22];
int hx[3000],ans[205];
int has(int num){
    if(hx[num])return hx[num];
    n++;hx[num]=n;return n;
}
void chan(int x,int w){//处理元素
    int i,j,l=strlen(wz[x]),xs=1,kl,ss;
    for(i=0;i<l;i++){
        if(wz[x][i]>='A'&&wz[x][i]<='Z'){
            kl=wz[x][i]-'A'+1;i++;
            if(wz[x][i]>='a'&&wz[x][i]<='z')kl=kl*100+wz[x][i]-'a'+1,i++;
            kl=has(kl);ss=0;
            while(wz[x][i]>='0'&&wz[x][i]<='9')ss=ss*10+wz[x][i]-'0',i++;
            if(ss==0)ss=1;i--;ss*=xs;
            a[kl][x]+=w*ss;
        }
        else if(wz[x][i]=='('){
            j=i+1;while(wz[x][j]!=')')j++;
            xs=wz[x][j+1]-'0';//其实这个 xs 的求法应该还要改一下,因为不一定是一位数(但是懒就不改了)
        }
        else if(wz[x][i]==')')xs=1;
    }
}
void init(){
    int i,j,l;
    scanf("%d%d",&c1,&c2);
    m=c1+c2;
    for(i=1;i<=m;i++){
        scanf("%s",wz[i]);
        if(i>c1)chan(i,-1);
        else chan(i,1);
    }
}
void guss(){//高斯消元 QWQ
    int i,j,k;double t;
    for(k=1;k<m;k++){//k: 第几列,now: 第几行
        for(i=now+1;i<=n&&fabs(a[i][k])<eps;i++);
        if(i>n){bj=1;break;}now++;
        if(now!=i)for(j=1;j<=m;j++)swap(a[i][j],a[now][j]);
        t=a[now][k];
        for(j=1;j<=m;j++)a[now][j]/=t;
        for(i=1;i<=n;i++)if(i!=now&&fabs(a[i][k])>eps){
            t=a[i][k];
            for(j=1;j<=m;j++)a[i][j]-=t*a[now][j];
        }
    }
}
void solve(){
    int i,j,jh;
    for(i=now+1;i<=n;i++)//列都消元完了,行呢?
        if(fabs(a[i][m])>eps){printf("Error");return;}
    if(bj){printf("Orz");return;}//氧化还原反应,归中不交叉处理不了(其实题目中是要特殊处理一个数据)
    for(i=1;i<=1000;i++){
        jh=0;
        for(j=1;j<=m;j++)
            if(fabs((int)(a[j][m]*i*(-1)+0.5)+a[j][m]*i)>eps){jh=1;break;}
        if(jh)continue;//四舍五入,是个类似整数
        for(j=1;j<=m;j++)ans[j]=(int)(a[j][m]*i*(-1)+0.5);
        ans[m]=i;
        if(ans[1]!=1)printf("%d",ans[1]);printf("%s",wz[1]);
        for(j=2;j<=c1;j++){
            printf("+");
            if(ans[j]!=1)printf("%d",ans[j]);
            printf("%s",wz[j]);
        }
        printf("=");
        if(ans[c1+1]!=1)printf("%d",ans[c1+1]);printf("%s",wz[c1+1]);
        for(j=c1+2;j<=m;j++){
            printf("+");
            if(ans[j]!=1)printf("%d",ans[j]);
            printf("%s",wz[j]);
        }
        return;
    }
    printf("Error");
}
int main(){init();guss();solve();return 0;}
分类: 文章

litble

苟...苟活者在淡红的血色中,会依稀看见微茫的希望

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注