HDOJ:1007---Quoit Design

HDOJ:1007—Quoit Design

题目描述

在这里插入图片描述

题目分析

这个题目描述的情景应该是我们大家都熟知的套圈游戏,如下图:
在这里插入图片描述
这题意思就是:我们要拿一个环去套在地上的玩具,这个环大小只能套中一个,去求他的最大的半径。
输入是一系列玩具的坐标,输出是环的最大半径。
这一题,看似复杂,其实只是一个典型的==“寻找最短点对问题”==,就是去寻找玩具之间最短的距离,最容易想到的是暴力遍历就可以去求,但是那样时间复杂度太高,我们采用分治的方法。

题解

解题思路参考了《编程之美——微软技术面试心得》这本书中的"寻找最近点对中的内容"。

AC代码如下:

/**
 * Problem 1007
 * Quoit Design
 * Date: 2023-4-15
*/

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;
const int MAXSIZE = 100000;
const int L = -1;
const int R = 1;

//玩具的结构体,存储了玩具坐标
typedef struct{
    double x;   //x坐标
    double y;   //y坐标
    int flag;  //区域标记(L R)
}Tp;

Tp Toy[MAXSIZE];
Tp assit[MAXSIZE];  //辅助数组 用来统计左右区域的点


//计算两玩具之间距离
double get_distance(Tp &Toy1,Tp &Toy2){
    return sqrt(pow(Toy1.x - Toy2.x,2)+pow(Toy1.y-Toy2.y,2));
}

//按照x从小到大排序
bool cmp_x(Tp &a,Tp &b){
    if(a.x == b.x)
        return a.y<b.y;
    else
        return a.x<b.x;
}

//按照y从小到大排序
bool cmp_y(Tp &a,Tp &b){
    if(a.y == b.y)
        return a.x<b.x;
    else
        return a.y<b.y;
}

//比较两个距离,返回小的
double min_dist(double &dist1,double &dist2){
    if(dist1>dist2)
        return dist2;
    return dist1;
}

//比较三个距离返回小的
double min_three(double &dist1,double &dist2,double &dist3){
    double min_d;
    min_d = dist1>dist2 ? dist2:dist1;
    min_d = min_d>dist3 ? dist3:min_d;
    return min_d;
}

//分治法求最小距离(我们需要的半径)
double get_mindist(int low,int high){
    double dist=0;
    int count = high - low;
    if(count==0){
        return 0;
    }else if(count==1){
        //含有两个玩具
        dist = get_distance(Toy[low],Toy[high]);
    }else if(count==2){
        //含有三个玩具
        double toy1,toy2,toy3;
        toy1 = get_distance(Toy[low],Toy[low+1]);
        toy2 = get_distance(Toy[low],Toy[high]);
        toy3 = get_distance(Toy[low+1],Toy[high]);

        dist = min_three(toy1,toy2,toy3);
    }else{
        //大于三个以上的情况
        double left_min,right_min,min;
        int mid = (low+high)/2;
        int p=0;

        //求左边最小的距离
        left_min = get_mindist(low,mid);
        
        //求右边最小的距离
        right_min = get_mindist(mid+1,high);

        dist = min_dist(left_min,right_min);

        /*找出在左区域和右区域的点,用flag来标记*/
        
        //左区域
        for(int i=low;i<=mid;i++){
            double left_coord = Toy[mid].x - dist;
            if(Toy[i].x>left_coord){
                assit[p].flag = L;  //属于左边部分
                assit[p].x = Toy[i].x;
                assit[p].y = Toy[i].y;
                p++;
            }
        }

        //右区域
        for(int i=mid+1;i<=high;i++){
            double right_coord = Toy[mid].x + dist;
            if(Toy[i].x<right_coord){
                assit[p].flag = R;  //属于左边部分
                assit[p].x = Toy[i].x;
                assit[p].y = Toy[i].y;
                p++;
            }
        }


        //找到的点再按y坐标排序
        sort(assit,assit+p,cmp_y);

        for(int i=0;i<p;i++){
            for(int j=1;(j<=7) && (i+j<p);j++){
                if(assit[i].flag != assit[i+j].flag){
                    min = get_distance(assit[i],assit[i+j]);
                    if(min<dist)
                        dist = min;
                }
            }
        }
    }

    return dist;
}

int main(){
    int toy_num;
    while(cin >> toy_num && toy_num!=0){
        double radius = 0;
        for(int i=0;i<toy_num;i++){
            Toy[i].flag = 0;
            cin >> Toy[i].x >> Toy[i].y;
        }
        sort(Toy,Toy+toy_num,cmp_x);

        radius = get_mindist(0,toy_num-1) / 2;   //其实求出的是直径,需要 /2
        printf("%.2lf\n",radius);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

压力小子呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值