给定一个圆上的点,找到可以用一条穿过圆心的线分隔的最少点数
Given points on a circle, find the minimum number of points which can be separated with a line through the center
假设给定一个度向量,表示单位圆上的点。您如何正式检查在一个具有直径的半圆中可以隔离的最少点数?我知道对于给定的一组数据点,可能有多个直径满足此 属性。没关系。我只对可以隔离的最小点数感兴趣,而不是特别是直径。它还需要计算效率高,因此它适用于大量点。我根据@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
,则递增右侧索引;如果角度差为 >180
,则递增左侧索引。 (right-left, length-right+left)
中的最小值是您想要的值。
请注意,扫描应以循环方式执行(您可以像这样添加带有 +360 的列表副本15, 45, 225, 375, 585
)
假设给定一个度向量,表示单位圆上的点。您如何正式检查在一个具有直径的半圆中可以隔离的最少点数?我知道对于给定的一组数据点,可能有多个直径满足此 属性。没关系。我只对可以隔离的最小点数感兴趣,而不是特别是直径。它还需要计算效率高,因此它适用于大量点。我根据@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
,则递增右侧索引;如果角度差为 >180
,则递增左侧索引。 (right-left, length-right+left)
中的最小值是您想要的值。
请注意,扫描应以循环方式执行(您可以像这样添加带有 +360 的列表副本15, 45, 225, 375, 585
)