三分法(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
#include
#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;
}


你可能感兴趣的:(ACM解题报告)