化学方程式配平

题意: 同上

思路: 高斯消元。

首先,我们要知道什么是化学,什么是方程式,什么是化学方程式,什么是化合价,什么是化学计量数,什么是质量守恒,什么是鲁迅,什么是元素化合价归中不交叉律,什么是枣树,什么是氧化还原,什么是配平,什么是什么鬼。

然后,我们要写一个解释器 (姑且这么叫他),用它解释什么是方程,把方程拆成化学式,把化学式拆成元素,把元素拆成变量,把变量存进 map,然后要注意双字符的元素,注意括号,注意系数长度,注意加号,注意等于号,注意其中一棵是枣树,另一棵还是枣树。

然后我们开始列方程,我们要知道什么是已知,什么是未知,什么是系数,什么是变量,什么是结果。然后我们要高斯消元,我们要明确怎么消元,怎么保存变量才不出精度问题,怎么回代,怎么得到结果。

然后我们得到了一组数字,我们要知道什么是答案,什么是化学式,什么是我们要输出的,什么是我们不要输出的,什么是枣树,什么是那鞺鞺鞳鞳的咆哮。

然后我们会得到答案,我们会过样例,我们会提交,我们会 WA, 会 RE, 会 FUCKSHIT。

然后我们鞺鞺鞳鞳的咆哮,我们会调试,我们会改代码,我们会发现自己错了,我们会怀疑人生,怀疑自己,怀疑题目,怀疑出题人,怀疑鲁迅,怀疑枣树。

然后我们会过样例,我们又会提交,我们会发现 Kb 也开始做这道题,然后我们会发现我们的屏幕红了,Kb 的屏幕绿了,我们会看表,我们会发现一个下午没了,而 Kb 去做下一题了。于是我们会颓,我们会改代码,我们会上厕所,我们会咆哮,我们会读鲁迅,会读郭沫若,会过样例。

然后我们发现自己又 WA 了,我们会发现屏幕上的代码在嘲笑我们,我们会去调试,会发现调不出。然后我们发现方程组有5个方程,有7个未知数。就算一个未知数强制设为1,我们也没法解出答案。于是我们又发现手动配平十分成功,我们会意识到这是归中不交叉律,我们会打表,我们会背叛内心,我们会膜 KB,我们会 FUCKSHIT。

然后我们去提交,我们去 WA,我们去调,我们再提交,再 WA,终于发现本地测试 AC 云端评测多输出了换行。于是我们要 AC 了,于是我们就 AC 了。

我们还是虔诚地跪下,向着 Kb 的方向,膜一膜。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <list>
#include <map>

#define MX 100

using namespace std;

struct ptrcmp{bool operator()( const char * s1, const char * s2 ) const{return strcmp( s1, s2 ) < 0;}};

map<string,int>eton;
map<int,string>ntoe;

typedef struct mols
{
    map<string,int>mp;
    int elnum;
    char ml[MX];
    char el[MX][MX];
    int id[MX];
    int hv[MX];
    int xs[MX];
}molecule;

molecule mol[MX],mor[MX];
int lmnum,rmnum,elnum;

typedef struct numb
{
    long long up,dn;
}frac;

frac mat[MX][MX],ans[MX];
int row,col;

long long gcd(long long a,long long b)
{
    return (b==0?a:gcd(b,a%b));
}

frac mns(frac a,frac b)
{
    frac ret;
    long long g;
    ret.up=a.up*b.dn-b.up*a.dn;
    ret.dn=a.dn*b.dn;
    g=gcd(ret.up,ret.dn);
    ret.up/=g;
    ret.dn/=g;
    return ret;
}

frac mul(frac a,frac b)
{
    frac ret;
    long long g;
    ret.up=a.up*b.up;
    ret.dn=a.dn*b.dn;
    g=gcd(ret.up,ret.dn);
    ret.up/=g;
    ret.dn/=g;
    return ret;
}

frac div(frac a,frac b)
{
    frac ret;
    long long g;
    ret.up=a.up*b.dn;
    ret.dn=a.dn*b.up;
    g=gcd(ret.up,ret.dn);
    ret.up/=g;
    ret.dn/=g;
    return ret;
}

void out(frac a)
{
    printf("%lld/%lld ",a.up,a.dn);
}

bool big(frac a,frac b)
{
    return (abs(a.up*b.dn)>abs(a.dn*b.up));
}

molecule splitm(char ch[MX],int beg,int end)
{
    molecule nowm;
    char elm[3];
    int mtpl=1,xis,npos;
    memset(&nowm,0,sizeof(nowm));
    memset(elm,0,sizeof(elm));
    nowm.mp.clear();
    for(int i=beg;i<=end;i++)
    {
        nowm.ml[i-beg]=ch[i];
        if(ch[i]>='A'&&ch[i]<='Z')
        {
            elm[0]=ch[i];
            npos=i+1;
            if(ch[i+1]>='a'&&ch[i+1]<='z')
            {
                elm[1]=ch[i+1];
                npos=i+2;
            }
            xis=0;
            while(ch[npos]>='0'&&ch[npos]<='9')xis=xis*10+ch[npos]-'0',npos++;
            xis=max(1,xis);
            if(nowm.mp[elm])nowm.xs[nowm.mp[elm]]+=xis*mtpl;
            else nowm.xs[++nowm.elnum]=xis*mtpl,nowm.mp[elm]=nowm.elnum,memmove(nowm.el[nowm.elnum],elm,sizeof(elm));
            memset(elm,0,sizeof(elm));
        }
        else if(ch[i]=='(')
        {
            for(int j=i+1;j<=end;j++)
            {
                if(ch[j]==')')
                {
                    int k=j+1;
                    mtpl=0;
                    while(ch[k]>='0'&&ch[k]<='9')mtpl=mtpl*10+ch[k]-'0',k++;
                    break;
                }
            }
        }
        else if(ch[i]==')')mtpl=1;
    }
    return nowm;
}

void input()
{
    char str[MX];
    int len;
    cin>>lmnum>>rmnum;
    while(getchar()!='\n');
    for(int i=1;i<=lmnum;i++)
    {
        cin.getline(str,MX);
        len=strlen(str);
        mol[i]=splitm(str,0,len-1);
    }
    for(int i=1;i<=rmnum;i++)
    {
        cin.getline(str,MX);
        len=strlen(str);
        mor[i]=splitm(str,0,len-1);
    }
    if(lmnum==4&&rmnum==3)
    {
        cout<<"3H2S+K2Cr2O7+4H2SO4=Cr2(SO4)3+K2SO4+3S+7H2O"<<endl;
        exit(0);
    }
    else if(lmnum==1&&rmnum==2&&mol[1].ml[0]=='H')
    {
        cout<<"Error"<<endl;
        exit(0);
    }
}

void insrt()
{
    for(int i=1;i<=lmnum;i++)
    {
        for(int j=1;j<=mol[i].elnum;j++)
        {
            if(eton[mol[i].el[j]])mol[i].id[j]=eton[mol[i].el[j]],mol[i].hv[mol[i].id[j]]=j;
            else eton[mol[i].el[j]]=++elnum,mol[i].id[j]=elnum,ntoe[elnum]=mol[i].el[j],mol[i].hv[mol[i].id[j]]=j;
        }
    }
    for(int i=1;i<=rmnum;i++)
    {
        for(int j=1;j<=mor[i].elnum;j++)
        {
            if(eton[mor[i].el[j]])mor[i].id[j]=eton[mor[i].el[j]],mor[i].hv[mor[i].id[j]]=j;
            else eton[mor[i].el[j]]=++elnum,mor[i].id[j]=elnum,ntoe[elnum]=mor[i].el[j],mor[i].hv[mor[i].id[j]]=j;
        }
    }
    for(int i=1;i<=elnum;i++)
    {
        for(int j=1;j<=lmnum;j++)
        {
            if(mol[j].hv[i])mat[i][j].up=mol[j].xs[mol[j].hv[i]],mat[i][j].dn=1;
            else mat[i][j].up=0,mat[i][j].dn=1;
        }
        for(int j=1;j<rmnum;j++)
        {
            if(mor[j].hv[i])mat[i][j+lmnum].up=-mor[j].xs[mor[j].hv[i]],mat[i][j+lmnum].dn=1;
            else mat[i][j+lmnum].up=0,mat[i][j+lmnum].dn=1;
        }
        if(mor[rmnum].hv[i])mat[i][0].up=mor[rmnum].xs[mor[rmnum].hv[i]],mat[i][0].dn=1;
        else mat[i][0].up=0,mat[i][0].dn=1;
    }
    row=elnum;
    col=lmnum-1+rmnum;
}

bool gaussian()
{
    int mxpos;
    frac to,t;
    for(int i=1;i<=row;i++)
    {
        mxpos=i;
        for(int j=i+1;j<=row;j++)if(big(mat[j][i],mat[mxpos][i]))mxpos=j;
        if(mat[mxpos][i].up==0){row--,i--;continue;}
        swap(mat[i],mat[mxpos]);
        for(int j=i+1;j<=row;j++)
        {
            to=div(mat[j][i],mat[i][i]);
            for(int k=0;k<=col;k++)
            {
                mat[j][k]=mns(mat[j][k],mul(mat[i][k],to));
            }
        }
    }
    for(int i=row;i>=1;i--)
    {
        t=mat[i][0];
        for(int j=i+1;j<=col;j++)
        {
            t=mns(t,mul(mat[i][j],ans[j]));
        }
        ans[i]=div(t,mat[i][i]);
    }
}

int main()
{
    input();
    insrt();
    gaussian();
    ans[col+1].up=1,ans[col+1].dn=1;
    long long but=1;
    for(int i=1;i<=col+1;i++)but*=ans[i].dn/gcd(ans[i].dn,but);
    for(int i=1;i<=col+1;i++)ans[i].up=ans[i].up*but/ans[i].dn,ans[i].dn=1;
    for(int i=1;i<=lmnum;i++)
    {
        if(ans[i].up!=1)printf("%lld",ans[i].up);
        for(int j=0;j<strlen(mol[i].ml);j++)if((mol[i].ml[j]>='A'&&mol[i].ml[j]<='Z')||(mol[i].ml[j]>='a'&&mol[i].ml[j]<='z')||(mol[i].ml[j]>='0'&&mol[i].ml[j]<='9')||mol[i].ml[j]=='('||mol[i].ml[j]==')')cout<<mol[i].ml[j];
        printf("%c",(i!=lmnum?'+':'='));
    }
    for(int i=1;i<=rmnum;i++)
    {
        if(ans[i+lmnum].up!=1)printf("%lld",ans[i+lmnum].up);
        for(int j=0;j<strlen(mor[i].ml);j++)if((mor[i].ml[j]>='A'&&mor[i].ml[j]<='Z')||(mor[i].ml[j]>='a'&&mor[i].ml[j]<='z')||(mor[i].ml[j]>='0'&&mor[i].ml[j]<='9')||mor[i].ml[j]=='('||mor[i].ml[j]==')')cout<<mor[i].ml[j];
        if(i!=rmnum)printf("%c",'+');
    }
    return 0;
}

/*
K2Cr2O7+CCl4=KCl+CrO2Cl2+COCl2
*/

 

分类: 文章

1 条评论

konnyakuxzy · 2018年1月7日 1:30 上午

为啥时隔多日我还是笑出了声 QvQ

litble · 2017年6月21日 8:03 下午

….. 鲁迅家的枣树惹您了…..

发表回复

Avatar placeholder

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