10.18T6 卡精度
溶液混合2176
【问题描述】
小Y由于高考的失败,被迫服从安排到化学系。对此小Y感到很无辜,于是他的大学四年都沉浸在了虚拟时空中(Orz…),甚至连配置溶液都不会。紧接着毕业论文横空出世。新的难题困扰这小Y。小Y经过几天废寝忘食的自学,跨时代地提出某一种溶液当浓度值等于某一个值的时候,这种溶液会对人产生一种神奇的效果。于是,某个月黑风高之时,小Y溜进实验室,偷出这种溶液若干瓶,决定自己配置一些神奇的溶液。当然,实验室的溶液浓度各不相同,怎么配成小Y需要的浓度呢……这于小Y可是大难题。
注:假设两种溶液混合后体积不发生变化。
【输入】
第一行,一个整数N,表示小Y偷出来的溶液瓶书,N小于等于50。
第二行,N个整数Ai,表示偷出来第I瓶溶液的浓度,Ai小于等于100.
第三行,N个整数Bi,表示偷出来第I瓶溶液的体积,Bi小于等于1000
第四行,一个整数,表示小Y想要的浓度。
【输出】
一个实数,它最多可以配成这种浓度的溶液多少体积,请保留5位小数。
【样例输入】
3
50 49 51
395 971 964
50
【样例输出】
2330.00000
【题目分析】贪心法
为了得到更多的溶液,首先把所有溶液倒在一起。
当然可能浓度不一定满足要求。于是要倒出一些原先加的溶液使得浓度满足要求。
显然,我们要倒掉尽可能少的溶液使得剩下溶液的浓度满足要求。
①若当前浓度大于要求的浓度:那么倒掉一些比当前浓度大的溶液,就能使溶液浓度下降。倒掉等体积的溶液,倒掉的溶液的浓度越大,浓度下降得越多。
因此我们得到算法:从浓度大的溶液开始一点一点倒,直到倒到满足要求,如果倒光了也不能满足要求就输出0,否则输出倒到满足要求时还剩下的溶液体积。
程序实现时,显然不可能“一点一点”倒,一开始应该一瓶一瓶倒,当发现倒掉某一瓶之后浓度下降到要求浓度之下那么,那么说明这瓶只要倒掉一部分,解一个方程,数学演算省略。
②若浓度小于要求的做法类似,在此省略。
【算法步骤】
①读入数据,计算全部溶液混合后的浓度nc;
②把溶液按浓度从小到大排序;
③若nc>c则从最浓的开始倒出;否则从最低的开始倒出
code:
1 #include<iostream> 2 #include<iomanip> 3 using namespace std; 4 double a[60],b[60],ans=0,c,sum=0,rz=0,cn; 5 int main() 6 { int i,j,k,n; 7 cin>>n; 8 for(i=1;i<=n;i++)cin>>a[i];//浓度 9 for(i=1;i<=n;i++){cin>>b[i];sum+=b[i];rz+=b[i]*a[i];} 10 cn=rz/sum;//全部混合后溶液的浓度 11 cin>>c;//想要的浓度 12 for(i=1;i<=n-1;i++)//按照浓度从小到大排序 13 for(j=i+1;j<=n;j++) 14 if(a[i]>a[j]){swap(a[i],a[j]);swap(b[i],b[j]);} 15 j=n; 16 while(cn>c)//浓度大于想要的浓度c 17 { double x; 18 x=double((rz-sum*c)/(a[j]-c));//计算应倒掉浓度为a[j]的体积 19 if(x<=b[j]){sum-=x;break;} 20 sum-=b[j];rz-=b[j]*a[j]; 21 cn=rz/sum; 22 j--; 23 } 24 i=1; 25 while(cn<c)//浓度小于想要的浓度c 26 { double x; 27 x=(sum*c-rz)/(c-a[i]); 28 if(x<=b[i]){sum-=x;break;} 29 sum-=b[i];rz-=b[i]*a[i]; 30 cn=rz/sum; 31 i++; 32 } 33 cout<<fixed<<setprecision(5)<<sum<<endl; 34 return 0; 35 }
over