化學方程式配平

這是個很可愛的東西~
我們把方程式中的每個元素的個數提出來,就可以列方程了。
沒錯,因爲方程是無數解的,所以我們把一個值設爲1,然後用分數存答案,最後算最小公倍數。
所以我們用到了分數類。
然後:

#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 55
#define maxp 27
using namespace std;
int gcd(int x,int y){return x%y==0?y:gcd(y,x%y);}
int lcm(int x,int y){
	if(x==0||y==0) return 0;
	int p=gcd(x,y);return x*y/p;
}
struct frac{//分數類 
	int a,b;
	frac operator = (int x){a=x,b=1;return *this;};
	frac operator = (const frac x){a=x.a,b=x.b;if(a!=0) reduce();return *this;};
	frac operator + (const frac x){
		if(x.a==0) return (frac){a,b};
		if(a==0) return (frac){x.a,x.b};
		return (frac){b*x.a+a*x.b,b*x.b};
	};
    frac operator - (const frac x){
    	if(x.a==0) return (frac){a,b};
		if(a==0) return (frac){-x.a,x.b};
		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){
		if(a==0){
			if(x.a>0&&x.b>0||x.a<0&&x.b<0) return true;
			if(x.a>0&&x.b<0||x.a<0&&x.b>0) return false;
		}
		if(x.a==0){
			if(a>0&&b>0||a<0&&b<0) return false;
			if(a>0&&x.b<0||a<0&&b>0) return true;
		}
		return a*x.b<b*x.a;
	};
	bool operator > (const frac x){
		if(a==0){
			if(x.a>0&&x.b>0||x.a<0&&x.b<0) return true;
			if(x.a>0&&x.b<0||x.a<0&&x.b>0) return false;
		}
		if(x.a==0){
			if(a>0&&b>0||a<0&&b<0) return false;
			if(a>0&&x.b<0||a<0&&b>0) return true;
		}
		return a*x.b>b*x.a;
	};
	bool operator == (const frac x){
		if(a==0) if(x.a==0) return true;else return false;
		if(x.a==0) if(a==0) return true;else return false;
		return a*x.b==b*x.a;
	};
	bool operator != (const frac x){
		if(a==0) if(x.a==0) return false;else return true;
		if(x.a==0) if(a==0) return false;else return true;
		return a*x.b!=b*x.a;
	};
	void reduce(){int x=gcd(a,b);a/=x,b/=x;}
};
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};
}
void Swap(frac &x,frac &y){
	frac Q=x;
	x=y;
	y=Q;
}  
int tot,p,x,len,total,num;
//tot 項數總數
//total 元素總數 
//num 方程總數 
frac Matr[maxn][maxn];
//Matr高斯消元矩陣 
char s[maxn];
struct Moon{
	char ch[1];
	int tot;
}part[maxn][maxn];
//每部分每個元素的對方程的貢獻 
char name[maxn][2];
char ch1,ch2;
int flag[maxn][maxp][maxp];
int ans[maxn];
void read(int &x,int &i){
	x=0;
	for (;i<=len&&isdigit(s[i]);i++) 
		x=x*10+s[i]-48;--i;
}
int get(){return (ch2==0)?0:ch2-'a'+1;}
bool pd(int x,int y){
	frac k,k1;
	for (int i=1;i<=tot;++i)
		if(Matr[y][i].a!=0){
			k=Matr[x][1]/Matr[y][1];
			break;
		}
	for (int i=2;i<=tot;++i)
		if(Matr[y][i].a!=0){
			k1=Matr[x][i]/Matr[y][i];
			if(k1!=k) return true;
		}else if(Matr[x][i].a!=0) return true;
	return false;
}
bool judge(int x){
	for (int i=1;i<x;++i)
		if(!pd(x,i)) return true;
	return false;
}
int main(){
	freopen("chemistry.in","r",stdin);
	freopen("chemistry.out","w",stdout);
//------------------------------------------- 	
//輸入處理 
	int i,j,k,q,sum;
	scanf("%s",s+1);
	len=strlen(s+1);tot=p=1;
	for (i=1;i<=len;++i){
		if(s[i]=='+') ++tot;
		if(s[i]=='=') ++tot,p=-1;
		if(s[i]<='Z'&&s[i]>='A'){
			ch1=s[i],ch2=0;
			if(s[i+1]<='z'&&s[i+1]>='a') ch2=s[i+1],read(x,i+=2),sum=((x==0)?1:x)*p;
			else if(isdigit(s[i+1])) read(x,i+=1),sum=((x==0)?1:x)*p;
			else sum=p;
			if(!flag[tot][ch1-'A'+1][get()]){
				part[tot][++part[tot][0].tot].ch[0]=ch1;
				part[tot][part[tot][0].tot].ch[1]=ch2;
				flag[tot][ch1-'A'+1][get()]=part[tot][0].tot;
			}
			part[tot][flag[tot][ch1-'A'+1][get()]].tot+=sum;
		}
		if(s[i]=='('){
			for (j=i+1;j<=len&&s[j]!=')';++j);
			read(x,j+=1);q=x;
			for (i++;i<=len&&s[i]!=')';++i){
				ch1=s[i],ch2=0;
				if(s[i+1]<='z'&&s[i+1]>='a') ch2=s[i+1],read(x,i+=2),sum=((x==0)?1:x)*p*q;
				else if(isdigit(s[i+1])) read(x,i+=1),sum=((x==0)?1:x)*p*q;
				else sum=p*q;
				if(!flag[tot][ch1-'A'+1][get()]){
					part[tot][++part[tot][0].tot].ch[0]=ch1;
					part[tot][part[tot][0].tot].ch[1]=ch2;
					flag[tot][ch1-'A'+1][get()]=part[tot][0].tot;
				}
				part[tot][flag[tot][ch1-'A'+1][get()]].tot+=sum;
			}i=j;
		}
	}
//------------------------------------------- 
//整理出所有元素 
	for (i=1;i<=tot;++i){
		for (j=1;j<=part[i][0].tot;++j){
			ch1=part[i][j].ch[0];
			ch2=part[i][j].ch[1];
			if(!flag[tot+1][ch1-'A'+1][get()]){
				name[++total][0]=part[i][j].ch[0];
				name[total][1]=part[i][j].ch[1];
				flag[tot+1][ch1-'A'+1][get()]=part[i][0].tot;
			}
		}
	}
//------------------------------------------- 
//處理高斯消元矩陣	
	for (i=1;i<=total;++i){
		++num;
		ch1=name[i][0],ch2=name[i][1];
		for (j=1;j<=tot;++j)
			if(flag[j][ch1-'A'+1][get()]) Matr[num][j]=part[j][flag[j][ch1-'A'+1][get()]].tot;
		if(flag[tot][ch1-'A'+1][get()]) Matr[num][tot]=-part[tot][flag[tot][ch1-'A'+1][get()]].tot;
		if(judge(num)) --num;
	}
	if(num==tot) --num;
//-------------------------------------------	
//高斯消元
	frac P;int r;
	for (i=1;i<num;++i){
		r=i;
		for (j=i+1;j<=num;++j)
			if(Abs(Matr[r][i])<Abs(Matr[j][i])) r=j;
		if(Abs(Matr[r][i])==(frac){0,1}){
			printf("No Solution\n");
			return 0;
		}
		if(r!=i)
			for (j=i;j<=tot;++j) 
				Swap(Matr[r][j],Matr[i][j]);
		for (j=i+1;j<=num;++j){
			if(Matr[j][i].a){
				P=Matr[i][i]/Matr[j][i];
				for (k=i;k<=tot;++k){
					Matr[j][k]=P*Matr[j][k];
					Matr[j][k]=Matr[j][k]-Matr[i][k];
				}
			}
		}
	}
	for (i=num;i>=1;--i){
		for (j=i+1;j<=num;++j){
			P=Matr[j][tot]*Matr[i][j];
			Matr[i][tot]=Matr[i][tot]-P;
		}
		Matr[i][tot]=Matr[i][tot]/Matr[i][i];
	} 
//-------------------------------------------
//把分母都統一成1
	int Lcm=1;
	for (i=1;i<=num;++i){
		if(Matr[i][tot].a)Matr[i][tot].reduce();
		Lcm=lcm(Lcm,Matr[i][tot].b);
	} 
	for (i=1;i<=num;++i)
		ans[i]=Matr[i][tot].a*Lcm/Matr[i][tot].b;
	ans[tot]=Lcm;
//-------------------------------------------
//輸出
	int inde=1;
	if(ans[1]>1)printf("%d",ans[1]);
	for (i=1;i<=len;++i){
		printf("%c",s[i]);
		if(s[i]=='+'||s[i]=='=')
			if(ans[++inde]>1) printf("%d",ans[inde]);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章