三分法(Ternary Search)求解凸(凹)函數的極值問題

前文解釋了三分法求極值的方法及核心代碼,而解決這類問題的重點就在於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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章