【数学】【计算几何】1453. 圆形靶内的最大飞镖数量

简介: 【数学】【计算几何】1453. 圆形靶内的最大飞镖数量

本文涉及知识点

数学 计算几何

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

Alice 向一面非常大的墙上掷出 n 支飞镖。给你一个数组 darts ,其中 darts[i] = [xi, yi] 表示 Alice 掷出的第 i 支飞镖落在墙上的位置。

Bob 知道墙上所有 n 支飞镖的位置。他想要往墙上放置一个半径为 r 的圆形靶。使 Alice 掷出的飞镖尽可能多地落在靶上。

给你整数 r ,请返回能够落在 任意 半径为 r 的圆形靶内或靶上的最大飞镖数。

示例 1 :

输入:darts = [[-2,0],[2,0],[0,2],[0,-2]], r = 2

输出:4

解释:如果圆形靶的圆心为 (0,0) ,半径为 2 ,所有的飞镖都落在靶上,此时落在靶上的飞镖数最大,值为 4 。

示例 2 :

输入:darts = [[-3,0],[3,0],[2,6],[5,4],[0,9],[7,8]], r = 5

输出:5

解释:如果圆形靶的圆心为 (0,4) ,半径为 5 ,则除了 (7,8) 之外的飞镖都落在靶上,此时落在靶上的飞镖数最大,值为 5 。

提示:

1 <= darts.length <= 100

darts[i].length == 2

-104 <= xi, yi <= 104

darts 中的元素互不相同

1 <= r <= 5000

计算几何

至少可以圈一个飞镖。我们来考虑两个或更多飞镖。

假定圆C可以圈n(n>1)个飞镖,我们轻微移动圆C,使得一个或多个飞镖从圆内移到圆上,令新圆为C1。如果有两个或更多的飞镖在圆上,则C2=C1。如果只有一个飞镖在圆上,假定此飞镖在A,保持A点不动,旋转圆C1,使得有一个到多个飞镖从圆内转到圆上,令新转到圆上的任意一个飞镖为B,新圆为C2。 → \rightarrow 只需要枚举两个飞镖都在圆上的圆。

枚举不同的飞镖A,B,有两个圆心都要枚举。AB的时候枚举一个,BA的时候枚举另外一个。

代码

struct vec;
struct point {
  point operator+(const vec& v);
  double x, y;
  point(double i, double j) :x(i), y(j) {}
};
struct vec
{
  vec(double tx, double ty)
  {
    x = tx;
    y = ty;
  }
  vec(const point& from, const point& to)
  {
    x = to.x - from.x;
    y = to.y - from.y;
  } 
  double x;
  double y;
  vec RatotaPlus90()
  {
    return { -y,x };
  }
  void ChangeToUint()
  {
    double len = sqrt(x * x + y * y);
    x /= len;
    y /= len;
  }
  vec& operator*=(double d)
  {
    x *= d;
    y *= d;
    return *this;
  }
};
point point::operator+(const vec& v)
{
  return { x + v.x,y + v.y };
}
//算两点距离
double dist(const point& a , const point& b) {
  return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
//计算圆心
point CircleCenter(point& a, point& b, int r) {
  //算中点
  point mid((a.x + b.x) / 2.0, (a.y + b.y) / 2.0);
  //AB距离的一半
  double d = dist(a, mid);
  //计算h
  double h = sqrt(r * r - d * d);
  //计算垂线
  vec ba(a, b);
  vec hd = ba.RatotaPlus90();
  hd.ChangeToUint();
  hd *= h;
  return mid + hd;
}
class Solution {
public:
  int numPoints(vector<vector<int>>& darts, int r) {
    int iCnt = 1;
    for (int i = 0; i < darts.size(); i++)
    {
      for (int j = 0; j < darts.size(); j++)
      {
        if (i == j)
        {
          continue;
        }
        point a(darts[i][0], darts[i][1]), b(darts[j][0], darts[j][1]);
        if (dist(a, b) > r * 2)
        {
          continue;
        }
        auto ptCenter = CircleCenter(a, b, r);
        int iCurCnt = 0;
        for (const auto& v : darts)
        {
          point tmp(v[0], v[1]);
          const double dDis = dist(ptCenter, tmp);
          if (dDis <= r)
          {
            iCurCnt++;
          }
        }
        iCnt = max(iCnt, iCurCnt);
      }
    }
    return iCnt;
  }
};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{
  assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    Assert(v1[i], v2[i]);
  }
}
int main()
{
  vector<vector<int>> darts;
  int r = 0;
  {
    Solution sln;
    darts = { {-8,9},{-2,1},{4,-4},{10,10},{-6,0},{-8,4},{-10,8},{-1,-2} }, r =11;
    auto res = sln.numPoints(darts, r);
    Assert(8, res);
  }
  {
    Solution sln;
    darts = { {-2,0},{2,0},{0,2},{0,-2} }, r = 2;
    auto res = sln.numPoints(darts, r);
    Assert(4, res);
  }
  {
    Solution sln;
    darts = { {-3,0},{3,0},{2,6},{5,4},{0,9},{7,8} }, r = 5;
    auto res = sln.numPoints(darts, r);
    Assert(5, res);
  }
}

2023年6月

struct point{
double x, y;
point(double i, double j) :x(i), y(j){}
};
//算两点距离
double dist(double x1, double y1, double x2, double y2){
return sqrt((x1 - x2)(x1 - x2) + (y1 - y2)(y1 - y2));
}
//计算圆心
point CircleCenter(point& a, point& b, int r){
//算中点
point mid((a.x + b.x) / 2.0, (a.y + b.y) / 2.0);
//AB距离的一半
double d = dist(a.x, a.y, mid.x, mid.y);
//计算h
double h = sqrt(rr - dd);
//计算垂线
point ba(b.x - a.x, b.y - a.y);
point hd(-ba.y, ba.x);
double len = sqrt(hd.xhd.x + hd.yhd.y);
hd.x /= len, hd.y /= len;
hd.x *= h, hd.y *= h;
return point(hd.x + mid.x, hd.y + mid.y);
}
class Solution {
public:
int numPoints(vector<vector>& darts, int r) {
int iMaxNum = 1;
for (int i = 0; i < darts.size(); i++)
{
point pt1 ( darts[i][0], darts[i][1] );
for (int j = 0; j < darts.size(); j++)
{
if (i == j)
{
continue;
}
//
if (dist(darts[i][0], darts[i][1], darts[j][0], darts[j][1]) > 2*r)
{
continue;
}
point pt2(darts[j][0], darts[j][1]);
//CircleCenter(pt1,pt2,r)和CircleCenter(pt2,pt1,r)的返回值不同
auto ptCenter = CircleCenter(pt1, pt2,r);
int iNum = 0;
for (const auto& v : darts)
{
if (dist(ptCenter.x, ptCenter.y, v[0], v[1]) > r)
{
continue;
}
iNum++;
}
iMaxNum = max(iMaxNum, iNum);
}
}
return iMaxNum;
}
};


扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。

https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程

https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版

https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。

相关文章
|
Serverless C语言 C++
【数学建模】利用C语言来实现 太阳赤纬 太阳高度角 太阳方位角 计算和求解分析 树木树冠阴影面积与种植间距的编程计算分析研究
【数学建模】利用C语言来实现 太阳赤纬 太阳高度角 太阳方位角 计算和求解分析 树木树冠阴影面积与种植间距的编程计算分析研究
266 1
|
4月前
|
算法
计算空间物体包围球的两种算法实现
计算空间物体包围球的两种算法实现
57 0
|
6月前
|
算法 Python
二维矩形件排样算法之最低水平线搜索算法实现
二维矩形件排样算法之最低水平线搜索算法实现
197 0
|
6月前
|
机器学习/深度学习 移动开发 算法
二维矩形件排样算法之最低水平线算法实现
二维矩形件排样算法之最低水平线算法实现
111 0
试题:最大的矩形(给定直方图里面积最大的矩形)
试题:最大的矩形(给定直方图里面积最大的矩形)
|
7月前
|
计算机视觉
OpenCV(三十三):计算轮廓面积与轮廓长度
OpenCV(三十三):计算轮廓面积与轮廓长度
295 0
|
7月前
|
机器学习/深度学习 存储 算法
C# | 凸包算法之Graham,快速找到一组点最外侧的凸多边形
这篇关于凸包算法的文章,本文使用C#和Graham算法来实现凸包算法。 首先消除两个最基本的问题: 什么是凸包呢? 凸包是一个包围一组点的凸多边形。凸多边形是指多边形中的每个内角都小于180度的多边形。 凸包算法有什么用呢? 凸包算法的作用是找到这个凸多边形,并且使用最少的点来绘制出它的轮廓。凸包算法在计算机图形学、计算几何和机器学习等领域中有着广泛的应用。
160 0
|
算法
秒懂算法 | 计算几何:圆
计算几何的基础是点积和叉积,它们定义了向量的大小和方向的关系,是其他计算几何概念和算法的出发点。在点积和叉积的基础上,本篇重点介绍圆覆盖。 计算几何题目的代码大多繁琐冗长,因此掌握模板代码是学习计算几何的关键。本篇精心组织了经典的几何模板
18139 1
秒懂算法 | 计算几何:圆
|
算法 图形学
计算机图形学 之 DDA直线算法(数值微分法)
计算机图形学 之 DDA直线算法(数值微分法)
445 0
|
前端开发 数据可视化 图形学
【数学篇】09 # 如何用仿射变换对几何图形进行坐标变换?
【数学篇】09 # 如何用仿射变换对几何图形进行坐标变换?
165 0
【数学篇】09 # 如何用仿射变换对几何图形进行坐标变换?