三分算法解决凸形或者凹形函数的极值;
二分解决具有单调性的函数的极值;
凹形的可以通过*-1转化为凸形
mid = (Left + Right) / 2
midmid = (mid + Right) / 2;
如果mid靠近极值点,则Right = midmid;
否则(即midmid靠近极值点),则Left = mid;
zoj3203
本题要求影子最长的长度。
在灯、人头、墙角成一条直线时影子长为a,在人到达墙角时影子长为b,我们可以写出人在这两点间时影子的方程:(x*H-D*h)/(x-D)+x,有数学知识可知这个方程在[a,b]之间是凸的,即先增加后减小,有极值,可以用三分法高效求解,注意一些边界条件。
边界x=[0,D/H*h]
#include<cstdio> #include<iostream> using namespace std; #define eps 1e-6 double H,h,D; double cal(double x) { return (x*H-D*h)/(x-D)+x; } void slove() { double left,right,mid,midmid; left=0,right=D/H*h; while(left+eps<right) { mid=(left+right)/2; midmid=(mid+right)/2; if(cal(mid)>=cal(midmid))right=midmid; else left=mid; } printf("%.3lf\n",cal(left)); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%lf%lf%lf",&H,&h,&D); slove(); } return 0; }
poj3301
题目要求是求最小的正方形,使之包含所有的点。
在0-90度范围内三分旋转的角度
旋转公式:x’=x*cos(phi)-y*sin(phi) y’=x*sin(phi)+y*cos(phi)
eps=1e-6 wa了,eps=1e-9就AC了,真坑
tip:
pi的表示方法
#define pi 3.1415926535897932384626
const double pi=3.1415926535897932384626;
const double pi=acos(-1.0); poj写成acos(-1) 会编译错误
#include<cstdio> #include<cmath> #include<iostream> using namespace std; #define eps 1e-9 #define pi 3.1415926535898 struct ss { double x,y; }a[50]; int n; double cal(double angle) { double x1,x2,y1,y2; x1=y1=10000; x2=y2=-10000; for(int i=0;i<n;i++) { double x=a[i].x*cos(angle)-a[i].y*sin(angle); double y=a[i].x*sin(angle)+a[i].y*cos(angle); x1=min(x1,x); y1=min(y1,y); x2=max(x2,x); y2=max(y2,y); } double d=max(y2-y1,x2-x1); return -d*d; } void slove() { double left,right,mid,midmid; left=0;right=pi/2; while(left+eps<right) { mid=(left+right)/2; midmid=(mid+right)/2; if(cal(mid)>=cal(midmid))right=midmid; else left=mid; } printf("%.2lf\n",-cal(left)); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=0;i<n;i++)scanf("%lf%lf",&a[i].x,&a[i].y); slove(); } return 0; }