Closest-pair problem: Difference between revisions
Content added Content deleted
(Go solution) |
(New method based on divide and conquer pseudocode.) |
||
Line 1,724: | Line 1,724: | ||
=={{header|R}}== |
=={{header|R}}== |
||
{{needs-review|R|Only brute force algorithms.}} |
|||
{{works with|R|2.8.1+}} |
{{works with|R|2.8.1+}} |
||
Brute force solution as per wikipedia pseudo-code |
Brute force solution as per wikipedia pseudo-code |
||
Line 1,840: | Line 1,839: | ||
</lang> |
</lang> |
||
Using dist function for brute force, but divide and conquer (as per pseudocode) for speed: |
|||
<lang R>closest.pairs.bruteforce <- function(x, y=NULL) |
|||
{ |
|||
if (!is.null(y)) |
|||
{ |
|||
x <- cbind(x,y) |
|||
} |
|||
d <- dist(x) |
|||
cp <- x[combn(1:nrow(x), 2)[, which.min(d)],] |
|||
list(p1=cp[1,], p2=cp[2,], d=min(d)) |
|||
} |
|||
closest.pairs.dandc <- function(x, y=NULL) |
|||
{ |
|||
if (!is.null(y)) |
|||
{ |
|||
x <- cbind(x,y) |
|||
} |
|||
xp <- x[order(x[,"x"]),] |
|||
yp <- x[order(x[,"y"]),] |
|||
.cpdandc.rec <- function(xp,yp) |
|||
{ |
|||
n <- dim(xp)[1] |
|||
if (n <= 4) |
|||
{ |
|||
closest.pairs.bruteforce(xp) |
|||
} |
|||
else |
|||
{ |
|||
xl <- xp[1:floor(n/2),] |
|||
xr <- xp[(floor(n/2)+1):n,] |
|||
xm <- xp[floor(n/2),"x"] |
|||
yl <- yp[which(yp[,"x"] <= xm),] |
|||
yr <- yp[which(yp[,"x"] > xm),] |
|||
cpl <- .cpdandc.rec(xl,yl) |
|||
cpr <- .cpdandc.rec(xr,yr) |
|||
if (cpl$d<cpr$d) cp <- cpl else cp <- cpr |
|||
dmin <- cp$d |
|||
ys <- yp[which(abs(xm - yp[,"x"]) < dmin),] |
|||
nys <- dim(ys)[1] |
|||
if (!is.null(nys) && nys > 1) |
|||
{ |
|||
for (i in 1:(nys-1)) |
|||
{ |
|||
k <- i + 1 |
|||
while (k <= nys && ys[i,"y"] - ys[k,"y"] < dmin) |
|||
{ |
|||
d <- sqrt((ys[k,"x"]-ys[i,"x"])^2 + (ys[k,"y"]-ys[i,"y"])^2) |
|||
if (d < cp$d) cp <- list(p1=ys[i,],p2=ys[k,],d=d) |
|||
k <- k + 1 |
|||
} |
|||
} |
|||
} |
|||
cp |
|||
} |
|||
} |
|||
.cpdandc.rec(xp,yp) |
|||
} |
|||
# Test functions |
|||
cat("How many points?\n") |
|||
n <- scan(what=integer(),n=1) |
|||
x <- rnorm(n) |
|||
y <- rnorm(n) |
|||
tstart <- proc.time()[3] |
|||
cat("Closest pairs divide and conquer:\n") |
|||
print(cp <- closest.pairs.dandc(x,y)) |
|||
cat(sprintf("That took %.2f seconds.\n",proc.time()[3] - tstart)) |
|||
plot(x,y) |
|||
points(c(cp$p1["x"],cp$p2["x"]),c(cp$p1["y"],cp$p2["y"]),col="red") |
|||
tstart <- proc.time()[3] |
|||
cat("\nClosest pairs brute force:\n") |
|||
print(closest.pairs.bruteforce(x,y)) |
|||
cat(sprintf("That took %.2f seconds.\n",proc.time()[3] - tstart)) |
|||
</lang> |
|||
Sample output |
|||
<pre> |
|||
How many points? |
|||
1: 500 |
|||
Read 1 item |
|||
Closest pairs divide and conquer: |
|||
$p1 |
|||
x y |
|||
1.68807938 0.05876328 |
|||
$p2 |
|||
x y |
|||
1.68904694 0.05878173 |
|||
$d |
|||
[1] 0.0009677302 |
|||
That took 0.43 seconds. |
|||
Closest pairs brute force: |
|||
$p1 |
|||
x y |
|||
1.68807938 0.05876328 |
|||
$p2 |
|||
x y |
|||
1.68904694 0.05878173 |
|||
$d |
|||
[1] 0.0009677302 |
|||
That took 6.38 seconds. |
|||
</pre> |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |