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

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));
}

你可能感兴趣的:(二分和三分)