R 给定圆上的点,求出通过圆心的直线可以分隔的最小点数

R 给定圆上的点,求出通过圆心的直线可以分隔的最小点数,r,math,geometry,graph-algorithm,computational-geometry,R,Math,Geometry,Graph Algorithm,Computational Geometry,假设给定了一个度向量,表示单位圆上的点。您如何正式检查,以确定在一个直径为1的半圆中可以隔离的最小点数?我知道对于给定的一组数据点,可能有多个直径满足此特性。没关系。我唯一感兴趣的是可以隔离的最小点数,而不是具体的直径。它还需要计算效率,因此它适用于大量点。我已经根据@d.b建议写了以下内容,但该算法对tst4失败 在R中 # Plots the points on a circle and attempts to find the minimum m (algorithm incorrect

假设给定了一个度向量,表示单位圆上的点。您如何正式检查,以确定在一个直径为1的半圆中可以隔离的最小点数?我知道对于给定的一组数据点,可能有多个直径满足此特性。没关系。我唯一感兴趣的是可以隔离的最小点数,而不是具体的直径。它还需要计算效率,因此它适用于大量点。我已经根据@d.b建议写了以下内容,但该算法对tst4失败

在R中

# Plots the points on a circle and attempts to find the minimum m (algorithm incorrect for tst )
min_dia <- function(degs, plot = T){
  library(dplyr)

  plot_circle <- function(x, y, r) {
    angles <- seq(0, 2*pi,length.out = 360)
    lines(r*cos(angles) + x, r*sin(angles) + y)
  }

  deg <- degs
  plot_boo <- plot

 # @d.b suggestion method for finding m
  temp <- abs((deg - min(deg) + 180) %% 360 - 180)
  m <- min(table(cut(temp, breaks = c(-180, 90, 180))))

  if(plot_boo == T){
    tm_deg <- c(0, 30, 45, 60, 90, 120, 135, 150, 180, 210, 225, 240, 270, 300, 315, 330)
    tm_rad <- (tm_deg * pi) / 180
    th <- (deg*pi)/180
    r <- 1
    x <- r*cos(th)
    y <- r*sin(th)
    windows.options(width = 600, height = 600)
    plot(x, y, xlim = c(-1.1, 1.1), ylim = c(-1.1, 1.1), pch = 20, xlab = "", ylab = "", main = "Plot of Given Data Points by Degrees")
    plot_circle(0, 0, 1)
    points(0, 0)
    text(r*cos(tm_rad), r*sin(tm_rad), labels = paste0(tm_deg), cex= 0.5, pos = 3)
  }

  return(m)
}

# Function to plot diameter by degrees
plot_dia <- function(deg){
  deg1 <- deg
  deg2 <- deg + 180
  th1 <- (deg1*pi)/180
  th2 <- (deg2*pi)/180
  x1 <- cos(th1)
  y1 <- sin(th1)
  x2 <- cos(th2)
  y2 <- sin(th2)
  lines(c(x1, x2), c(y1, y2))
}

# Testing
tst1 <- c(15, 45, 20) # m = 0
tst2 <- c(15, 45, 200) # m = 1
tst3 <- c(15, 46, 114, 137, 165, 187, 195, 215, 271, 328) # m = 3
tst4 <- c(36, 304, 281, 254, 177, 59, 47, 158, 244, 149, 317, 235, 345, 209, 204,
          156, 325, 95, 215, 267)

# Implementation
min_dia(tst1)
plot_dia(90) # eyeball and plot to check

min_dia(tst2)
plot_dia(190) # eyeball and plot to check

min_dia(tst3)
plot_dia(110) # eyeball and plot to check

min_dia(tst4)
plot_dia(150) # m is probably 2
对于我在代码中提供的15度、45度和225度的三个点,我可以用一条线分隔的最小点数m为1

对于15、20、25度的分数,答案显然是0

如果您能提供有效的算法来解决这个最小化问题,我们将不胜感激

更新:

这是一个图,如果你要运行R代码以及一条线的例子,它说明了你可以分离的最小点数,为1

更新:


我还更新了上面的代码,它允许我们绘制数据点,推测一个使m最小的直径,并按度绘制直径

这里有一个蛮力方法。只要在所有角度0.5:359.5处画一条线,看看哪个角度的值最小

bar = function(degs){
    CUTS = sapply(0:359 + 0.5, function(D){
        temp = ((degs - D + 180) %% 360 - 180)
        min(table(cut(temp, breaks = c(-180, 0, 180))))
    })

    D = (0:359 + 0.5)[which.min(CUTS)]
    m = min(CUTS)

    plot(0, 0, type = "n",
    xlim = c(-1.5, 1.5), ylim = c(-1.5, 1.5),
    ann = FALSE, axes = FALSE, asp = 1)
    plotrix::draw.circle(0, 0, 1)

    degs = degs * pi/180
    xs = cos(degs)
    ys = sin(degs)

    x1 = cos(D * pi/180)
    y1 = sin(D * pi/180)

    x2 = cos((D * pi/180) + pi)
    y2 = sin((D * pi/180) + pi)

    lines(c(x1, x2), c(y1, y2))
    points(xs, ys, pch = 19)
    points(0, 0)
    return(c(min_num = m, angle = D))
}

tst4 <- c(36, 304, 281, 254, 177, 59, 47, 158, 244, 149, 317, 235,
             345, 209, 204, 156, 325, 95, 215, 267)

bar(degs = tst4)
# min_num   angle 
#     5.0   145.5 

如果点未排序,则按角度排序

使用双指针方法浏览列表。如果角度差为180,则增加右索引。从右到左的最小距离,右+左的长度是您想要的值


请注意,扫描应以循环方式进行。您可以通过+360加法添加列表副本,如15、45、225、375、585

我在可视化问题时遇到困难…如果要运行示例,我刚刚上载了一个绘图。这有助于说明问题吗@IgnacioVazquez AbramsSo你想让每一半的点大致均匀地分布在中心吗?不是特别的。我想通过把圆分成两半来找出我能把它分成两半的最小点数。这有助于澄清问题吗@IgnacioVazquez Abrams您可以按角度对这些点进行排序,并为每个点找到另一半直线与圆相交的索引。对于蛮力方法,这将在日志N而不是^2上提供。不确定这在R中是否可行,但至少在优雅的方式下是这样。虽然它可能对那个特定的例子有效,但它似乎在一般情况下不起作用@d、 b当使用给定的度数尝试解决方案时:deg如果您使用我在说明中提供的绘图仪绘制这些度数,我不明白您如何可能使用穿过中心的任何直线分隔2个点。您的算法失败tst 4。我已经更新了上面的一些代码。我也在努力尝试实施MBo评论,但我在努力分配。非常感谢您对R代码的任何帮助。谢谢您的详细建议。现在正在做这个。