• 圆形靶内的最大飞镖数量


    题目

    1453. 圆形靶内的最大飞镖数量

    墙壁上挂着一个圆形的飞镖靶。现在请你蒙着眼睛向靶上投掷飞镖。
    投掷到墙上的飞镖用二维平面上的点坐标数组表示。飞镖靶的半径为 r 。
    请返回能够落在 任意 半径为 r 的圆形靶内或靶上的最大飞镖数。

    数据规模:点的个数N<=100,r<=5000

    对题目进行解析,就是要找一个圆心,使得以该圆心为中心、r为半径的圆能够覆盖(在圆内或者圆上)更多的给定的点。求能覆盖的最多的点的数目。

    思路

    由于圆心是在二维坐标平面,是无限可能的,所以不能直接用暴力的方法。

    换一种思路,如果找到这个圆(这个圆能覆盖最多的点),那么一定满足至少有两个点在这个圆上。用反证法可以证明:
    如果有0个点在这个圆上,可以通过移动圆心,使得有1个点在圆上,并且被覆盖的点不会变少。
    如果有1个点在这个圆上,可以通过移动圆心,使得有2个点在圆上,并且被覆盖的点不会变少。可以通过固定这个点在圆上,然后进行旋转。

    所以遍历两两的点,找到他们的圆心,求这个圆心覆盖的点的个数。

    从圆上两个点找到圆心的公式是:
    Paper.Paper_工具.15

    实现代码如下:

    class Solution {
        double precision=1e-10;
        public int numPoints(int[][] points, int r) {
            int n=points.length;
            int max=1;
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(i==j){
                        continue;
                    }
                    double[] center=getCenter(i,j,points,r);
                    if(center==null){
                        continue;
                    }
                    int cnt=getCnt(center,r,points);
                    max=Math.max(max,cnt);
                }
            }
            return max;
        }
    
        private boolean onOrIn(int[] p,double[] center,int r){
            //发现有一个5.000000000000001
            return getDist(new double[]{p[0],p[1]},center)-r<=precision;
        }
    
        private int getCnt(double[] center,int r,int[][] points){
            int res=0;
            for(int[] p:points){
                if(onOrIn(p,center,r)){
                    res++;
                }
            }
            return res;
        }
        private double[] getCenter(int i,int j,int[][] points,int r){
            double[] p0=new double[]{points[i][0],points[i][1]};
            double[] p1=new double[]{points[j][0],points[j][1]};
            double dist=getDist(p0,p1);
            if(dist>2*r){
                return null;
            }
            double a=dist/2;
            double h=Math.sqrt(r*r-a*a);
            double[] OM=new double[]{(p0[0]+p1[0])/2.0,(p0[1]+p1[1])/2.0};
            double[] MC=new double[]{p0[1]-p1[1],-(p0[0]-p1[0])};
            double factor=h/getDist(MC,new double[]{0,0});
            MC[0]*=factor;
            MC[1]*=factor;
            return new double[]{OM[0]+MC[0],OM[1]+MC[1]};
        }
    
        private double getDist(double[] p1,double[] p2){
            double x=p1[0]-p2[0];
            double y=p1[1]-p2[1];
            return Math.sqrt(x*x+y*y);
        }
    }
    

    还有另一种叫做Angular Sweep的算法,以后有空再看看。

    参考:
    关于为什么一定会有两个点在圆上
    Angular Sweep
    Angular Sweep

  • 相关阅读:
    Linux TCP/IP 连接查看和问题解决
    Linux Tomcat 7.0 管理员登录时"401 Unauthorized" 问题解决方法
    Tomcat 性能监控工具jvisualvm, JConsole
    Tomcat 实战-调优方案
    Linux Tomcat8 访问管理页面 403 Access Denied
    docker redis
    Spring Boot 定时任务
    Nginx rewrite使用
    五 python 发送邮件
    关于注解继承性的一个例子
  • 原文地址:https://www.cnblogs.com/FannyChung/p/13021730.html
Copyright © 2020-2023  润新知