BZOJ 2458 最小三角形(分治)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2458

题意:平面上有N个点,输出周长最小的三角形的周长。

思路:按照x升序。分治。然后就是合并。设两边分治得到的答案为C。那么对于在中间线两边的点到中线的x距离小于C。将这些点按照y升序。对于每个点,找到y坐标差也在C范围内的暴力一下就行。

 


 
struct point
{
    double x,y;
     
    void get()
    {
        RD(x,y);
    }
     
    double len()
    {
        return sqrt(x*x+y*y);
    }
     
    point operator-(point a)
    {
        point p;
        p.x=x-a.x;
        p.y=y-a.y;
        return p;
    }
};
 
point a[N];
int n;
 
double len(point p) {return p.len();}
 
int cmp1(point a,point b)
{
    return a.x<b.x;
}
 
int cmp2(point a,point b)
{
    return a.y<b.y;
}
 
double cal(int L,int R)
{
    double ans=dinf;
    int i,j,k;
    for(i=L;i<=R;i++) for(j=i+1;j<=R;j++)
    {
        for(k=j+1;k<=R;k++) 
        {
            upMin(ans,len(a[i]-a[j])+len(a[i]-a[k])+len(a[j]-a[k]));
        }
    }
    return ans;
}
 
point b[N],c[N],Q[N];
int bNum,cNum;
int qNum;
 


 
double combine(double x,int M,int L,int R)
{
    bNum=cNum=0;
    int now=M;
    while(a[M].x-a[--now].x<=x&&now>=L) b[++bNum]=a[now];
    now=M;
    while(a[++now].x-a[M].x<=x&&now<=R) c[++cNum]=a[now];
    c[++cNum]=a[M];
    sort(b+1,b+1+bNum,cmp2);
    sort(c+1,c+1+cNum,cmp2);
    double ans=dinf;
    int q=1,p=1;
    qNum=0;
    int i,j,k;
    FOR1(i,bNum)
    {
        while(q<=cNum&&b[i].y-c[q].y>x) q++;
        p=q;
        while(p<=cNum&&c[p].y-b[i].y<=x) Q[++qNum]=c[p++];
        for(j=1;j<=qNum;j++) for(k=1;k<=j-1;k++)
        {
            upMin(ans,len(b[i]-Q[j])+len(Q[j]-Q[k])+len(b[i]-Q[k]));
        }
        qNum=0;
    }
    q=1;p=1;cNum=0;
    now=M;
    while(a[++now].x-a[M].x<=x&&now<=R) c[++cNum]=a[now];
    b[++bNum]=a[M];
    sort(b+1,b+1+bNum,cmp2);
    sort(c+1,c+1+cNum,cmp2);
    FOR1(i,cNum)
    {
        while(q<=bNum&&c[i].y-b[q].y>x) q++;
        p=q;
        while(p<=bNum&&b[p].y-c[i].y<=x) Q[++qNum]=b[p++];
        for(j=1;j<=qNum;j++) for(k=1;k<=j-1;k++)
        {
            upMin(ans,len(c[i]-Q[j])+len(Q[j]-Q[k])+len(c[i]-Q[k]));
        }
        qNum=0;
    }
    return ans;
}
 
double DFS(int L,int R)
{
    double ans;;
    int M=(L+R)>>1;
    if(R-L+1>5)
    {
        ans=min(DFS(L,M+1),DFS(M+1,R));
        upMin(ans,combine(ans,M+1,L,R));
    }    
    else ans=cal(L,R);
    return ans;
}
 
int main()
{
    RD(n);
    int i;
    FOR1(i,n) a[i].get();
    sort(a+1,a+n+1,cmp1);
    double ans=DFS(1,n);
    PR(ans);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值