首页 > 代码库 > poj 2006 Litmus Test 【即zoj 2351:计算酸的PH】

poj 2006 Litmus Test 【即zoj 2351:计算酸的PH】

公式:  pH = -log10 [H+]  PH值根据氢离子浓度求出 ,【这里的 [H+] 浓度是摩尔每升为单位的


Ka = [H+] [acid ions] / [acid]   平衡常数K等于分解的氢离子和酸根离子乘积与未分解的酸分子的比值 


输入格式:   Ka :常数   ori :初始酸浓度    m :1摩酸分子完全溶解 分解出氢离子数    n :1摩酸分子完全溶解 分解出氢离子数【注意是完全溶解】

【这题需要特别注意的是】指数形式是可以直接输入的。如用scanf 或者 printf要用%e输入。 


题目给出了一个比较好的例子,用了甲酸的例子:甲酸的平衡常数Ka1.6 * 10-4,1摩尔甲酸完全溶解放出1摩尔 [H+] 和1摩尔酸根离子,如果初始浓度是0.1 moles/L,但是不知道确切有多少甲酸溶解了,设为x摩尔,最后平衡的时候,就有0.1 - x moles/L的甲酸分子(未溶解),[H+] 和酸根离子各 x moles/L。


注意:我上面一直强调的两个不同的概念,完全溶解和不完全溶解,完全溶解就是每个酸分子都水解成 [H+] 和酸根离子了,不完全溶解就是一个动态平衡的过程。我记得高中化学里面讲到的,其实不存在完全水解的酸,就算是强电解质。。。回到题目上来,题目给出的m和n都是完全电解环境下,这样就相当于给出了一个酸分子分解后的 [H+] 和酸根离子比例。比如m=4,n=1,就是一个 [H+] 和4个酸根离子,比如硫酸H2SO4。。。


这样就可以设未知数列方程了,我们假设每L溶解了x摩尔的该酸,就有

Ka = mx*nx / ori-x ,变换以后就是 Ka*(ori-x) = mn*x*x ,再就是 mnx^2 + Ka*x - Ka*ori = 0,这样就变成了一个一元二次方程,就可以开始解方程了。

x = [sqrt(Ka*Ka+4*m*n*Ka*ori)-Ka] / 2mn,这里还没完,因为我们只是得到了每L溶解了x摩尔的该酸,还不是最后要求出的 [H+] ,所以还得乘上一个m。


消去分母里面的m,这样才变成了大家博客里面津津乐道的:

i=-log10((sqrt(k*k+4*a*m*n*k)-k)/2/n);
printf("%.3f\n",i);

所以,要完全弄懂还是要花一番功夫的。另外多说一句,c语言中log是以e为底的,要想以10为底,要么除以一个log((double)10)换底,要么见下面的代码。


AC代码:

#include<stdio.h>
#include<math.h>
#include<iostream>

using namespace std;

int main()
{
    double Ka;   //平衡常数
    double ori;  //原始酸浓度
    int m;       //1摩酸分子 完全溶解 分解出氢离子数
    int n;		 //1摩酸分子 完全溶解 分解出酸根离子数
    double H;    //最后计算Ph值的氢离子数
	
	while(1)
	{
		cin>>Ka;
		cin>>ori;
		cin>>m;
		cin>>n;

		if(Ka==0&&ori==0&&m==0&&n==0)
			break;

		H=(sqrt(Ka*Ka+4*m*n*Ka*ori)-Ka)/(2*n);
        printf("%.3f\n",-log10(H));
	}
	
	
	return 0;
}


写博客,我觉得我得说实话,也顺便发表一个感想。

这道题目是我做ACM以来遇到的最难理解题意的一道题,对于一个高中化学一塌糊涂,又脑袋不好使的我来说还是太难了,也可能是我本身就做题太少的缘故。。但是不论怎么说,这道题的题意理解却是难点。。

不过,我也遇到一个很有意思的现象,网上很多人说这道题水,可我读这道题的题目就用了个把小时,看来是我智商太低呀,不然就是我英语太差,读不懂题目。。。但是当我看到他们粘贴的代码很相似(其中包括一些看似大牛的人),而对这题的题目没有一个明确分析的时候(甚至只粘贴了一个代码在上面),我大概明白了是怎么回事了。。。做ACM还是得踏实啊,装B不能当饭吃。。。