好的,所以说有一个网格,我存储为二维数组,即10×10。
int[][] grid = new int[10][10];
网格的原点位于左下方,就像普通的x y平面一样,网格中心有一个半径为5的圆(5,5),如下所示:
我想通过这个数组,基本上检查圆圈内的哪些点,但我不想遍历整个数组。默认情况下,角落上的每个点都不会出现在圆圈中,所以我想忽略这些点,类似于靠近角落的点等等。
只是圆圈中的点。我有一个更大的网格和循环不必要的东西,我已经知道不在圈内会浪费时间。有没有办法做到这一点?因为,鉴于我已经知道了圆的半径和中心,所以应该有一个很好的简单方法来遍历圆中的那些点,并将它们从0更改为-1,例如。
否则,我将失去100 - 25π≈21.46%的时间。
更好的清晰度:我已经知道我可以用正方形限制圆圈,然后环绕该正方形中的点并检查距离圆心的每个点距离(x ^ 2 + y ^ 2< r ^ 2),但这是我想要避免的,因为每次检查不在圆圈中的位时,由于每次检查不在圆圈中的位时会产生不断的开销。
答案 0 :(得分:1)
好的,经过长时间的讨论,这是解决方案。您扫描四分之一切片的一个轴,计算需要向外填充该四分之一的扩展,然后一次填充所有四个季度。
int n = 1000;
// you will need to think yourself about the odd number or elements
int r = n / 2;
int r2 = r * r;
在两种情况下将(0,0)放在矩阵的中心,优化的解决方案可能如下所示:
int[][] grid0 = new int[n][n];
for (int i = 0; i < r; i++) {
double m = Math.sqrt(r2 - i * i);
for (int j = 0; j < m; j++) {
grid0[r + i][r + j] = 1;
grid0[r + i][r - j] = 1;
grid0[r - i][r + j] = 1;
grid0[r - i][r - j] = 1;
}
}
如其他地方所述,填充圆的扩展名是用O(n)计算的。
以下是简单的验证:
int[][] grid1 = new int[n][n];
// you will need to think yourself about the even number
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if ((i - r) * (i - r) + (j - r) * (j - r) < r2) {
grid1[i][j] = 1;
}
}
}
两者都产生相同数量的填充点。
超过10000次执行的时间测量(在时间循环之外进行数组初始化):
优化后的6.0s
详尽无遗的15.6s
所以,我承认存在差异,这是一个令人惊讶的差异。虽然为了公平比较,后一个片段也应该使用圆的四分之一片段。
可以使用某种内存复制例程进一步加速优化的解决方案,将值从0填充到计算点而不是普通循环,但这超出了范围。