CF 782B 和 HDU 4717 经典移点问题 【 二分 和 三分 时间】

来源:互联网 发布:bi数据产品经理 编辑:程序博客网 时间:2024/06/05 10:11

CF 782B 传送门

/** @Cain*/const int maxn = 1e5+5;const db eps = 1e-7;int a[maxn],b[maxn];int main(){    int n;    scanf("%d",&n);    for(int i=1;i<=n;i++){        scanf("%d",&a[i]);    }    for(int i=1;i<=n;i++){        scanf("%d",&b[i]);    }    db l = 0, r = inf , mid;    while(r - l > eps){        mid = (r+l)/2.0;        db maxx = -inf, minn = inf;        for(int i=1;i<=n;i++){            db xl = a[i]*1.0 - b[i]*mid;            db xr = a[i]*1.0 + b[i]*mid;            maxx = max(maxx,xl);  //千万不要找错了,是找最小的进 //行比较, 而不是最大的, 既是往左和右移动距离小的那两个. //如果直接找最大的两个点则有可能有交叉部分.            minn = min(minn,xr);        }        if(fabs(maxx - minn) < eps)            break;        else if(maxx < minn) r = mid;        else l = mid;    }    printf("%.12lf\n",mid);}

HDU 4717 传送门
//思路:在平面中任意两个点的距离一定是先减小, 后增大的, 不信可以画出来看一看. 所以满足单峰函数, 所以就可以用三分来做.

/** @Cain*/const int maxn = 3e2+5;const db eps = 1e-6;int x[maxn],y[maxn],vx[maxn],vy[maxn];int n;int cas = 1;db cal(db t){    db res = 0;    for(int i=1;i<=n;i++){        for(int j=i+1;j<=n;j++){            db x1 = x[i]*1.0+vx[i]*t;            db y1 = y[i]*1.0+vy[i]*t;            db x2 = x[j]*1.0+vx[j]*t;            db y2 = y[j]*1.0+vy[j]*t;            db maxx = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));            res = max(maxx,res);        }    }    return res;}void solve(){    scanf("%d",&n);    for(int i=1;i<=n;i++){        scanf("%d%d%d%d",&x[i],&y[i],&vx[i],&vy[i]);    }    db l = 0, r = inf,len;    db lm,rm;    while(r - l > eps){        len = (r-l)/3.0;         lm = l + len;        rm = r - len;        db dislm = cal(lm);        db disrm = cal(rm);        if(dislm < disrm) r = rm;        else l = lm;    }    printf("Case #%d: %.2f %.2f\n",cas++,l,cal(l));}