二分法用来解决单调函数的极值问题,而三分法用来解决凸函数的极值问题。
所以在使用三分的时候要注意函数具有凹凸性
模板:
double cal() { //.....具体计算根据题目要求实现 return 0.0; } void solve() { double left,right,mid1,mid2,ans,flg1,flg2; left=0.0;right=1000.0; while(right-left>eps) { mid1=(2*left+right)/3; mid2=(left+2*right)/3; flg1=cal();//具体实现 flg2=cal(); if(flg1>flg2) right=mid2; else left=mid1; } ans=cal();//left }
例题:
hdu 3400
题意:平面上有两条线段AB和CD,在AB上行走的速度为P,CD上行走的速度为Q,其他区域行走的速度为R,问从A走到D的最短时间。
//============================================================================ // Name : hdu3400三分.cpp // Author : xinge008 // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <string> using namespace std; const double eps=1e-12; double P,Q,R; struct Node{ double x,y; }; Node A,B,C,D; Node dist(Node n1,Node n2) { Node ans; ans.x=(n1.x+n2.x)/2; ans.y=(n1.y+n2.y)/2; return ans; } double cal(Node n1,Node n2) { double t1=(n1.x-n2.x)*(n1.x-n2.x); double t2=(n1.y-n2.y)*(n1.y-n2.y); return sqrt(t1+t2); } double run1(Node da) { Node left=C,right=D; double max=100,min=0; // double max=cal(left,right)/Q,min=0; while(fabs(max-min)>eps) { Node mid1=dist(left,right); Node mid2=dist(mid1,right); min=cal(mid1,da)/R+cal(mid1,D)/Q; max=cal(mid2,da)/R+cal(mid2,D)/Q; if(min<=max) right=mid2; else left=mid1; } return max; } double run2() { Node left=A,right=B; double max=100,min=0; // double min=0,max=cal(A,B)/P; while(fabs(max-min)>eps) { Node mid1=dist(left,right); Node mid2=dist(mid1,right); min=cal(mid1,A)/P+run1(mid1); max=cal(mid2,A)/P+run1(mid2); if(min<=max) right=mid2; else left=mid1; } return max; } void gao() { int T; scanf("%d",&T); while(T--) { scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y); scanf("%lf%lf%lf%lf",&C.x,&C.y,&D.x,&D.y); scanf("%lf%lf%lf",&P,&Q,&R); printf("%.2lf\n",run2()); } } int main() { gao(); return 0; }
HDU3714
题意:函数F[x]=max{Si(x)} (i=0,1,2,3,...,n) 其中Si(x)为二次函数, 求函数F[X]的最小值。
//============================================================================ // Name : 三分.cpp // Author : xinge008 // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <cstring> #include <string> #include <cmath> #include <algorithm> #include <cstdio> using namespace std; const int maxn=10010; const double eps = 1e-12; struct node{ double a,b,c; }data[maxn]; double _Max(double a,double b) { if(a>b) return a; return b; } double cal1(int i,double da) { return data[i].a*da*da+data[i].b*da+data[i].c; } double cal2(double x,int n) { double ans=-1e10; for(int i=1;i<=n;i++) ans=_Max(ans,cal1(i,x)); return ans; } void cal(int n) { double left,right,ans,mid1,mid2; left=0;right=1000.0; while(right-left>eps) { //在此是高精度的要求 mid1=(2*left+right)/3; mid2=(left+2*right)/3; double flg1=cal2(mid1,n); double flg2=cal2(mid2,n); if(flg1>flg2) { left=mid1; }else { right=mid2; } } ans=cal2(left,n); printf("%.4lf\n",ans); } int main() { int T; scanf("%d",&T); while(T--) { int num; scanf("%d",&num); for(int i=1;i<=num;i++) { scanf("%lf%lf%lf",&data[i].a,&data[i].b,&data[i].c); } cal(num); } return 0; }