前文解釋了三分法求極值的方法及核心代碼,而解決這類問題的重點就在於f函數的求得,比如HDU 2438,ZJU3203,PKU3301,Ural1874,lightoj1146/1240(解題報告)這些題目比較容易求出,但CodeForces185B是個例外,函數已經給出題意是給出a,b,c三個整數以及x,y,z和的最大值S,在x^a*y^b*z^c取得最大值時反求x,y,z的值,這種情況下我們可以在三分x的同時,三分y和z,求解時我們轉化爲求f=alnx+blny+clnz的最大值,同時要注意x,y,z等於0的情況,題目中已給出:ln(0)=-∞,同時此題要求精度較高,附菜鳥代碼(聽說此題可用某某函數得出一個很簡單的結論,貌似前隊友數學帝就是這麼搞的= =。)
#include<stdio.h>
#include<math.h>
#define esp 1e-12
#define INF 99999999
int s,a,b,c;
double cal(double tem,int flag){
double l=0,r=tem;
while(r-l>esp){
double temp1,temp2,temp3,temp4;
double mid=(r+l)/2.0;
double midmid=(r+mid)/2.0;
if(mid==0) temp1=-INF;
else temp1=log(mid);
if(tem-mid==0) temp2=-INF;
else temp2=log(tem-mid);
if(midmid==0) temp3=-INF;
else temp3=log(midmid);
if(tem-midmid==0) temp4=-INF;
else temp4=log(tem-midmid);
if((b*temp1+c*temp2)-(b*temp3+c*temp4)>esp) r=midmid;
else l=mid;
}
if(flag==1){
printf("%0.10f %0.10f",l,tem-l);
//return;
}
double temp5,temp6;
if(l==0) temp5=-INF;
else temp5=log(l);
if(tem-l==0) temp6=-INF;
else temp6=log(tem-l);
return b*temp5+c*temp6;
}
void work(){
double l=0,r=s;
while(r-l>esp){
double temp1,temp2;
double mid=(r+l)/2.0;
double midmid=(r+mid)/2.0;
if(mid==0) temp1=-INF;
else temp1=log(mid);
if(midmid==0) temp2=-INF;
else temp2=log(midmid);
if((cal(s-mid,0)+a*temp1)-(cal(s-midmid,0)+a*temp2)>esp) r=midmid;
else l=mid;
}
printf("%0.10f ",l);
cal(s-l,1);
}
int main()
{
scanf("%d%d%d%d",&s,&a,&b,&c);
work();
return 0;
}