这是以下相反的问题:
Determine position of number in a grid of numbers centered around 0 and increasing in spiral
这两种方式是: index - >坐标(完成,见上面的问题) 坐标 - > index(我的问题)
我坚持的部分是从原始坐标获取扇区而没有庞大的丑陋逻辑分支。
是否有一种简单的算术方法来确定扇区?如何反转此函数以获取坐标对并返回索引?
答案 0 :(得分:2)
如果你在螺旋线上绘制素数的位置,这是一个Ulam spiral它有一些有趣的属性。
25|26|27|28|29|30
24| 9|10|11|12|31
23| 8| 1| 2|13|32
22| 7| 0| 3|14|33
21| 6| 5| 4|15|34
20|19|18|17|16|35
........ |36
首先要注意的是方形数字的位置。它们位于对角线上,左上对角线为奇数方块,右下对角线为偶数方块。
25| | | | |
| 9| | | |
| | 1| | |
| | 0| | |
| | | 4| |
| | | |16|
........ |36
让我们看看这些坐标(x,y)
的对角线 (-2,3)| | | | | (3,3)
| (-1,2)| | | (2,2)|
| | (0,1)| (1,1)| |
| | (0,0)| | |
|(-1,-1)| |(1,-1)| |
(-2,-2)| | | |(2,-2)|
| | | | |(3,-3)
首先注意对角线,如果y> = 0且x = 1-y,我们位于左上角,值为(2 y-1)^2
或(1-2x)^2
。
如果y <0且x = -y,我们在右下对角线,值为(2x)^ 2 = 4x ^ 2或(-2y)^ 2 = 4y ^ 2.
如果y&gt; = 0且x&gt; = 1-y,xpos = x + y-1,我们在顶部的水平行上。该值为(2 y-1)^2 + pos
。
底部的水平行具有y <0且x> = y,x <= - y。平方数左边的步数是pos = -x-y。值为4y^2+pos
。
类似的计算适用于垂直行。这些都可以在函数
中编码function spiral(x,y) {
var pos,squ;
// Horizontal row at top
if(y>=0 && ( x >= 1-y && x<y ) ) {
pos = x+y-1;
squ = (2 *y-1)*(2*y-1);
// Horizontal row at bottom
} else if( y < 0 && ( x >= y && x<= -y ) ) {
pos = -x-y;
squ = 4*y*y;
// Vertical row on right
} else if( x >0 ) {
pos = -x-y;
squ = 4*x*x;
// Vertical row on left
} else {
squ = (1-2*x)*(1-2*x);
pos = x+y-1;
}
return squ+pos;
}
我在fiddle进行了javascript实施。这样就可以将数字螺旋上升到99.
稍微简单的功能是
spiral = function(x,y) {
var res;
var u = x+y;
var v = x-y;
if(u>0) {
if(v>=0) {
x <<= 1;
res = x*(x-1) + v;
} else {
y <<= 1;
res = y*(y-1) + v;
}
} else {
if(v<0) {
x <<= 1;
res = -x*(1-x) - v;
} else {
y <<= 1;
res = -y*(1-y) - v;
}
}
return res;
}
在这里,你告诉你在对角线方向上的移动距离。两个数字的符号告诉您您所在的行业。我们可以通过查找x = y行上的值来获取每个水平/垂直边的基数。去东北方向的是2,12,30(即1 * 2,3 * 4,5 * 6),西南方向是6,20,42(即2 * 3,4 * 5,6 *) 7)。这些方程是2*x*(2*x-1)
和-2*x*(1-2*x)
或使用y相同。为了获得每个点的索引,我们可以简单地将v添加或减去这些索引。
这使用1次乘法,2次比较,1位移位和4次加法。有可能删除其中一个添加内容,但我相信你需要一个乘法和2个比较。
答案 1 :(得分:0)
考虑在不改变方向的情况下采取的步数。您会发现该序列为1,1,2,2,3,3,4,4,5,5 ......模式应该是显而易见的。现在经过四条这样的直边后,你几乎回到了同一个角落。因此,您可以找到连接这些角的线的索引:
c0: 0, 1+1+2+2, …+3+3+4+4, …+5+5+6+6, …+7+7+8+8, …
c1: 1, …+1+2+2+3, …+3+4+4+5, …
c2: 1+1, …
c3: 1+1+2, …
对于其中每一项,您都可以编写公式。第一个是这样的:
c0[i] = sum((2*i - 1) + (2*i - 1) + (2*i) + (2*i)) = sum(8*i - 2)
现在ask Wolfram Alpha。它会告诉你
c0[i] = 4i² + 2i
因此,如果有人为您提供索引 n ,您可以通过solving the above equation for i解决上次访问该边缘线的问题,采取正解决方案,然后将其四舍五入为整数。您可以对其他边缘线执行相同操作,或者在最坏的情况下接受围绕中心旋转一整圈。整个回合意味着四个星际区域,你不想一个接一个地去。
Wolfram Alpha还打印序列的前几个元素:6,20,42,72,110。您可以将其用于look this up in OEIS,并查找注释中的A002943
以顺时针方向螺旋写入0,1,2,...序列在4个对角线中的一个上给出数字。
但我可以向你保证,它适用于逆时针螺旋... ...
答案 2 :(得分:0)
这将是一个很晚的答案,但我还是要回答,因为我本人已经遇到了这个确切的问题,却从未真正找到解决其他问题的可靠方法。这是对所有其他答案的免费解答,因为为什么不这样做
以下是我找到的解决方案的伪代码:
// n is the number in the spiral at (x, y)
// m is an intermediate step towards calculating n
m = 2 * max(abs(x), abs(y)) - (x > -y) // this relies on booleans being evaluated as 0 or 1
n = m^2 + abs(x + (-1)^m * floor((m + 1) / 2)) + abs(y - (-1)^m * floor(m / 2))
在Python 3中:(最新测试在3.7.0中进行)
import math
def number_in_spiral(x, y):
m = 2 * max(abs(x), abs(y)) - (x > -y)
return m * m + abs(x + pow(-1, m) * math.floor((m + 1) / 2)) + \
abs(y - pow(-1, m) * math.floor(m / 2))
在JavaScript中:
function number_in_spiral(x, y)
{
var m = 2 * Math.max(Math.abs(x), Math.abs(y)) - (x > -y);
return m * m + Math.abs(x + Math.pow(-1, m) * Math.floor((m + 1) / 2)) +
Math.abs(y - Math.pow(-1, m) * Math.floor(m / 2));
}
请记住,此公式中的y向上增加,在很多情况下并不理想。在这种情况下,可以在公式的每个实例中将输入y乘以-1,或将y替换为-y。
我希望这对某人有用。如果不是这样,当我不可避免地从4年后回到这个问题时,这至少对我有用。