首页 > 代码库 > 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输入。
题目给出了一个比较好的例子,用了甲酸的例子:甲酸的平衡常数Ka是1.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不能当饭吃。。。