11.04_点圆关系

点圆关系

问题描述

点圆关系处理平面上点与圆之间的基本关系,包括点到圆的距离、点在圆内外的判断等。常用于范围查询和碰撞检测问题。

基本操作

算法思想

  1. 使用圆心和半径表示圆
  2. 基于距离进行判断
  3. 适用于范围和位置判断
  4. 时间复杂度

代码实现

class Circle {
public:
    Point center;
    double radius;
    
    Circle(Point c = Point(), double r = 0) : center(c), radius(r) {}
    
    // 判断点在圆内
    bool contains(const Point& p) const {
        return center.distance(p) <= radius + EPS;
    }
    
    // 判断点在圆上
    bool onCircle(const Point& p) const {
        return abs(center.distance(p) - radius) < EPS;
    }
    
    // 点到圆的最短距离
    double distanceToPoint(const Point& p) const {
        double d = center.distance(p);
        return max(0.0, d - radius);
    }
    
    // 计算圆的面积
    double area() const {
        return M_PI * radius * radius;
    }
    
    // 计算圆的周长
    double perimeter() const {
        return 2 * M_PI * radius;
    }
};
class Circle {
    Point center;
    double radius;
    static final double EPS = 1e-10;
    static final double PI = Math.PI;
    
    Circle(Point c, double r) {
        this.center = c;
        this.radius = r;
    }
    
    // 判断点在圆内
    boolean contains(Point p) {
        return center.distance(p) <= radius + EPS;
    }
    
    // 判断点在圆上
    boolean onCircle(Point p) {
        return Math.abs(center.distance(p) - radius) < EPS;
    }
    
    // 点到圆的最短距离
    double distanceToPoint(Point p) {
        double d = center.distance(p);
        return Math.max(0.0, d - radius);
    }
    
    // 计算圆的面积
    double area() {
        return PI * radius * radius;
    }
    
    // 计算圆的周长
    double perimeter() {
        return 2 * PI * radius;
    }
}
class Circle:
    def __init__(self, center: Point = Point(), radius: float = 0):
        self.center = center
        self.radius = radius
        self.EPS = 1e-10
        self.PI = math.pi
    
    # 判断点在圆内
    def contains(self, p: Point) -> bool:
        return self.center.distance(p) <= self.radius + self.EPS
    
    # 判断点在圆上
    def on_circle(self, p: Point) -> bool:
        return abs(self.center.distance(p) - self.radius) < self.EPS
    
    # 点到圆的最短距离
    def distance_to_point(self, p: Point) -> float:
        d = self.center.distance(p)
        return max(0.0, d - self.radius)
    
    # 计算圆的面积
    def area(self) -> float:
        return self.PI * self.radius * self.radius
    
    # 计算圆的周长
    def perimeter(self) -> float:
        return 2 * self.PI * self.radius

时间复杂度分析

操作 时间复杂度 空间复杂度
点在圆内判断
点在圆上判断
点到圆距离
面积周长计算

应用场景

  1. 范围查询
  2. 碰撞检测
  3. 区域判断
  4. 面积计算
  5. 几何构造

注意事项

  1. 浮点数精度
  2. 边界情况
  3. 特殊情况
  4. 坐标范围
  5. 数值稳定性

常见变形

  1. 圆与点集
class Solution {
public:
    // 找出圆内的所有点
    vector<Point> pointsInCircle(const Circle& circle, 
                               const vector<Point>& points) {
        vector<Point> result;
        for (const Point& p : points) {
            if (circle.contains(p)) {
                result.push_back(p);
            }
        }
        return result;
    }
    
    // 找出离圆最近的k个点
    vector<Point> nearestKPoints(const Circle& circle,
                               const vector<Point>& points,
                               int k) {
        vector<pair<double, Point>> distances;
        for (const Point& p : points) {
            distances.emplace_back(circle.distanceToPoint(p), p);
        }
        
        partial_sort(distances.begin(), 
                    distances.begin() + k,
                    distances.end());
        
        vector<Point> result;
        for (int i = 0; i < k && i < distances.size(); i++) {
            result.push_back(distances[i].second);
        }
        return result;
    }
};
class Solution {
    // 找出圆内的所有点
    public List<Point> pointsInCircle(Circle circle, Point[] points) {
        List<Point> result = new ArrayList<>();
        for (Point p : points) {
            if (circle.contains(p)) {
                result.add(p);
            }
        }
        return result;
    }
    
    // 找出离圆最近的k个点
    public List<Point> nearestKPoints(Circle circle, Point[] points, int k) {
        PriorityQueue<Point> pq = new PriorityQueue<>(
            (a, b) -> Double.compare(
                circle.distanceToPoint(a),
                circle.distanceToPoint(b)
            )
        );
        
        for (Point p : points) {
            pq.offer(p);
        }
        
        List<Point> result = new ArrayList<>();
        for (int i = 0; i < k && !pq.isEmpty(); i++) {
            result.add(pq.poll());
        }
        return result;
    }
}
class Solution:
    # 找出圆内的所有点
    def points_in_circle(self, circle: Circle, 
                        points: List[Point]) -> List[Point]:
        return [p for p in points if circle.contains(p)]
    
    # 找出离圆最近的k个点
    def nearest_k_points(self, circle: Circle,
                        points: List[Point], k: int) -> List[Point]:
        return sorted(points,
                     key=lambda p: circle.distance_to_point(p))[:k]
  1. 最小圆覆盖
class Solution {
public:
    // 计算包含所有点的最小圆
    Circle minCircleCover(vector<Point>& points) {
        if (points.empty()) return Circle();
        if (points.size() == 1) return Circle(points[0], 0);
        
        // 随机打乱点的顺序
        random_shuffle(points.begin(), points.end());
        
        Circle circle(points[0], 0);
        for (int i = 1; i < points.size(); i++) {
            if (!circle.contains(points[i])) {
                circle = Circle(points[i], 0);
                for (int j = 0; j < i; j++) {
                    if (!circle.contains(points[j])) {
                        circle = makeCircleFromTwo(points[i], points[j]);
                        for (int k = 0; k < j; k++) {
                            if (!circle.contains(points[k])) {
                                circle = makeCircleFromThree(
                                    points[i], points[j], points[k]
                                );
                            }
                        }
                    }
                }
            }
        }
        return circle;
    }

private:
    Circle makeCircleFromTwo(const Point& p1, const Point& p2) {
        Point center((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
        return Circle(center, center.distance(p1));
    }
    
    Circle makeCircleFromThree(const Point& p1, const Point& p2, 
                             const Point& p3) {
        // 三点确定一个圆
        double a = p2.x - p1.x, b = p2.y - p1.y,
               c = p3.x - p1.x, d = p3.y - p1.y;
        double e = a * (p1.x + p2.x) + b * (p1.y + p2.y);
        double f = c * (p1.x + p3.x) + d * (p1.y + p3.y);
        double g = 2 * (a * (p3.y - p2.y) - b * (p3.x - p2.x));
        
        if (abs(g) < EPS) return Circle();
        
        Point center(
            (d * e - b * f) / g,
            (a * f - c * e) / g
        );
        return Circle(center, center.distance(p1));
    }
};
class Solution {
    // 计算包含所有点的最小圆
    public Circle minCircleCover(Point[] points) {
        if (points.length == 0) return new Circle(new Point(), 0);
        if (points.length == 1) return new Circle(points[0], 0);
        
        // 随机打乱点的顺序
        List<Point> list = Arrays.asList(points);
        Collections.shuffle(list);
        points = list.toArray(new Point[0]);
        
        Circle circle = new Circle(points[0], 0);
        for (int i = 1; i < points.length; i++) {
            if (!circle.contains(points[i])) {
                circle = new Circle(points[i], 0);
                for (int j = 0; j < i; j++) {
                    if (!circle.contains(points[j])) {
                        circle = makeCircleFromTwo(points[i], points[j]);
                        for (int k = 0; k < j; k++) {
                            if (!circle.contains(points[k])) {
                                circle = makeCircleFromThree(
                                    points[i], points[j], points[k]
                                );
                            }
                        }
                    }
                }
            }
        }
        return circle;
    }
    
    private Circle makeCircleFromTwo(Point p1, Point p2) {
        Point center = new Point(
            (p1.x + p2.x) / 2,
            (p1.y + p2.y) / 2
        );
        return new Circle(center, center.distance(p1));
    }
    
    private Circle makeCircleFromThree(Point p1, Point p2, Point p3) {
        // 三点确定一个圆
        double a = p2.x - p1.x, b = p2.y - p1.y,
               c = p3.x - p1.x, d = p3.y - p1.y;
        double e = a * (p1.x + p2.x) + b * (p1.y + p2.y);
        double f = c * (p1.x + p3.x) + d * (p1.y + p3.y);
        double g = 2 * (a * (p3.y - p2.y) - b * (p3.x - p2.x));
        
        if (Math.abs(g) < EPS) return new Circle(new Point(), 0);
        
        Point center = new Point(
            (d * e - b * f) / g,
            (a * f - c * e) / g
        );
        return new Circle(center, center.distance(p1));
    }
}
class Solution:
    # 计算包含所有点的最小圆
    def min_circle_cover(self, points: List[Point]) -> Circle:
        if not points:
            return Circle()
        if len(points) == 1:
            return Circle(points[0], 0)
        
        # 随机打乱点的顺序
        random.shuffle(points)
        
        circle = Circle(points[0], 0)
        for i in range(1, len(points)):
            if not circle.contains(points[i]):
                circle = Circle(points[i], 0)
                for j in range(i):
                    if not circle.contains(points[j]):
                        circle = self.make_circle_from_two(
                            points[i], points[j]
                        )
                        for k in range(j):
                            if not circle.contains(points[k]):
                                circle = self.make_circle_from_three(
                                    points[i], points[j], points[k]
                                )
        return circle
    
    def make_circle_from_two(self, p1: Point, p2: Point) -> Circle:
        center = Point(
            (p1.x + p2.x) / 2,
            (p1.y + p2.y) / 2
        )
        return Circle(center, center.distance(p1))
    
    def make_circle_from_three(self, p1: Point, p2: Point, 
                             p3: Point) -> Circle:
        # 三点确定一个圆
        a = p2.x - p1.x
        b = p2.y - p1.y
        c = p3.x - p1.x
        d = p3.y - p1.y
        e = a * (p1.x + p2.x) + b * (p1.y + p2.y)
        f = c * (p1.x + p3.x) + d * (p1.y + p3.y)
        g = 2 * (a * (p3.y - p2.y) - b * (p3.x - p2.x))
        
        if abs(g) < self.EPS:
            return Circle()
        
        center = Point(
            (d * e - b * f) / g,
            (a * f - c * e) / g
        )
        return Circle(center, center.distance(p1))
test1 文章被收录于专栏

test11

全部评论

相关推荐

02-14 00:25
中南大学 Java
题目如图这题我觉得最好就是用对k二分来做,但是我总是过不了测试用例,牛客上的那测试用例老长一串又复制不了,有没有大佬帮我看下代码哪里有问题呀?感激不尽!!代码如下:public&nbsp;class&nbsp;Main&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Scanner&nbsp;in&nbsp;=&nbsp;new&nbsp;Scanner(System.in);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;n=in.nextInt(),m=in.nextInt();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TreeSet&nbsp;set=new&nbsp;TreeSet<>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in.nextLine();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;wall=in.nextLine();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;i&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(wall.charAt(i)=='W')&nbsp;set.add(i);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(set.ceiling(0)==null)&nbsp;System.out.print(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;left=-1,right=n+1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(left+1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;mid=(left+right)/2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(check(set,mid,m))&nbsp;right=mid;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;left=mid;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.print(right);&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;boolean&nbsp;check(TreeSet&nbsp;set,int&nbsp;k,int&nbsp;m)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;idx=set.ceiling(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;i&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idx+=k;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(set.ceiling(idx)==null)&nbsp;return&nbsp;true;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&nbsp;&nbsp;&nbsp;}}
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客企业服务