三分求极值 - Minimum Bounding Box

三分是指之前接触过的一个算法,但是没有用来写过题。
最近 a t a b c 130 at abc130 atabc130 F F F题出到了,结果压根没想到要用三分。

题意:对于 n n n个点,要求使得这 n n n个点 x x x轴上的最大值-最小值和 y y y轴上的最大值-最小值乘积最小。通过样例可以发现时间显然可以是小数。那么就是函数求极值的问题了。
事实上,我并不会证明此题为什么是单峰函数。但是用三分可以忽略这些,直接解决。(这样求极值肯定是用三分。

至于三分。
我们考虑这样一个单峰函数(三分只适用于单峰函数。

在这里插入图片描述
此时区间为 [ l , r ] [l,r] [l,r],两个三等分点 m 1 m1 m1, m 2 m2 m2,如果 f ( m 1 ) > f ( m 2 ) f(m1)>f(m2) f(m1)>f(m2),那么极值点所在区间应该是 [ m 1 , r ] [m1,r] [m1,r]。反之,所在区间为 [ L , m 2 ] [L,m2] [L,m2]
求极小值的话全都反过来。这个动手画画图就可以判断了,没有必要特意记。

唯一需要记住的是:
三分的写法和二分的写法有所不同。

  1. 它是以循环 300 300 300次或者其他次数来得到的,否则容易 T L E TLE TLE,我比较喜欢 300 300 300
  2. 处理答案的时候,直接取每次计算的最小值(指求极小值。
  3. 如果是求极值点,左右 l , r l,r l,r皆可。(暂未实践。

次数主要决定于原区间长度 x ( 2 3 ) k ≈ 0 x(\frac{2}{3})^{k}≈0 x(32)k0, k k k是多少次数就应该大致是多少,最好多一些。
这题就可以解决了,求答案直接计算即可,存储一下每个点的方向。

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef unsigned long long ULL;
typedef long long ll;

int n;

struct node{
    double x,y;
    char dir[4];
}A[100050];

double cal(double x){
    double ml=1e10,mr=-1e10,mu=-1e10,md=1e10;
    FOR(i,1,n){
        pair<double,double>tmp;
        tmp.first=A[i].x,tmp.second=A[i].y;
        switch(A[i].dir[0]){
            case 'U':tmp.second+=x;break;
            case 'D':tmp.second-=x;break;
            case 'L':tmp.first-=x;break;
            case 'R':tmp.first+=x;break;
        }
        ml=min(ml,tmp.first);
        mr=max(mr,tmp.first);
        mu=max(mu,tmp.second);
        md=min(md,tmp.second);
    }
    //cout<<x<<" "<<(mr-ml)*(mu-md)<<endl;
    return (mr-ml)*(mu-md);
}

int main(){
    cin>>n;
    FOR(i,1,n){
        scanf("%lf%lf%s",&A[i].x,&A[i].y,A[i].dir);
    }
    double l=0,r=1e12,ans=1e18;
    FOR(k,0,300){
        double m1=(l+(r-l)/3),m2=(l+(r-l)*2/3);
        double tmp1=cal(m1),tmp2=cal(m2);
        if(tmp1>tmp2)l=m1;
        else r=m2;
        ans=min(ans,tmp1);
        ans=min(ans,tmp2);
    }
    printf("%.10f",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值