2011-11-21 56 views
7

我想通过以下方式来填充n * n(n为奇数)矩阵:简单的方法来填充这个矩阵?

_ _ _ 23 22 21 20 
_ _ 24 10 9 8 37 
_ 25 11 3 2 19 36 
26 12 4 1 7 18 35 
27 13 5 6 17 34 _ 
28 14 15 16 33 _ _ 
29 30 31 32 _ _ _ 

什么是一个简单的方法来做到这一点使用数学

+2

我们可以假定'N'是奇数? – Szabolcs

+0

@Szabolcs,对不起,你当然可以。 –

+1

只是好奇:你打算如何使用它? –

回答

12

有了这个辅助函数:

Clear[makeSteps]; 
makeSteps[0] = {}; 
makeSteps[m_Integer?Positive] := 
    [email protected][ 
    Table[#, {m}] & /@ {{-1, 0}, {-1, 1}, {0, 1}, {1, 0}, {1, -1}, {0, -1}}, 1]; 

我们可以构建矩阵

constructMatrix[n_Integer?OddQ] := 
    Module[{cycles, positions}, 
    cycles = (n+1)/2; 
    positions = 
     Flatten[FoldList[Plus, cycles + {#, -#}, makeSteps[#]] & /@ 
      Range[0, cycles - 1], 1]; 
    SparseArray[Reverse[positions, {2}] -> Range[Length[positions]]]]; 

要获得您所描述的矩阵,使用

constructMatrix[7] // MatrixForm 

背后的想法这是检查连续数字1的位置跟随的模式。你可以看到这些形成了循环。第零个循环是微不足道的 - 在位置{0,0}处包含数字1(如果我们从中心计数位置)。下一个循环是通过在位置{1,-1}处获取第一个数字(2)并逐个添加以下步骤来形成的:{0, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 0}(当我们在中心附近移动时)。第二个周期是类似的,但我们必须从{2,-2}开始,重复每个前面的步骤两次,并添加第六步(向上),只重复一次:{0, -1}。第三个循环是类似的:从{3,-3}开始,重复所有步骤3次,除了{0,-1},其仅重复两次。辅助功能makeSteps使过程自动化。在主要功能中,我们必须将所有位置一起收集起来,然后将其添加到{cycles, cycles},因为它们是从位于中心的位置计算的,位置为{cycles,cycles}。最后,我们构建了这些职位中的SparseArray

+0

@ Mr.Wizard我加了一些解释 –

+0

做得非常好。 –

+0

@ Mr.Wizard One可以删除双重'Tranpose'并使用'{cycles +#,cycles - #}&'而不是'{#, - #}&'来缩短代码,代价是性能受损。 –

8

我不知道Mathematica的语法,但我想你可以使用一种算法是这样的:

start in the middle of the matrix 
enter a 1 into the middle 
go up-right (y-1/x+1) 
set integer iter=1 
set integer num=2 
while cursor is in matrix repeat: 
    enter num in current field 
    increase num by 1 
    repeat iter times: 
     go left (x-1/y) 
     enter num in current field 
     increase num by 1 
    repeat iter times: 
     go down-left (x-1/y+1) 
     enter num in current field 
     increase num by 1 
    repeat iter times: 
     go down (x/y+1) 
     enter num in current field 
     increase num by 1 
    repeat iter times: 
     go right (x+1/y) 
     enter num in current field 
     increase num by 1 
    repeat iter times: 
     go up-right (x+1/y-1) 
     enter num in current field 
     increase num by 1 
    repeat iter-1 times: 
     go up (x/y-1) 
     enter num in current field 
     increase num by 1 
    go up-up-right (y-2/x+1) 
    increase iter by 1 

你也可以很容易地转换算法成一个功能版本或成尾递归。如果你不超出界限,你将不得不在while循环中检查。如果n是奇数,那么你可以只计数NUM了,而:

m = floor(n/2) 
num <= n*n - (m+m*m) 

我敢肯定,有一个简单的算法,但是这是最直观的一个给我。

+1

尽管类似这样的东西当然有用,而且很简单,但我认为问题的关键在于如何利用Mathematica的内置功能和函数式编程配置来创建更简单,更紧凑的东西:-) – Szabolcs

+0

尽管我的版本独立的,我只是意识到,这是我结束了,相同的算法,只是程序上完成。 +1。 –

+0

@Leonid我必须承认,在阅读本书的过程中我迷失了方向,并且认为“我只是等待一个* Mathematica *的答案。” PeterT:+1 –

4

在对角线上开始幻数为1,右往上走可以从

f[n_] := 2 Sum[2 m - 1, {m, 1, n}] + UnitStep[n - 3] Sum[2 m, {m, 1, n - 2}] 

In := [email protected]@5 
Out := {2, 8, 20, 38, 62} 

可以带着这应该很容易建立一个SparseArray。我会仔细研究一下,看看它有多难。

+1

你可以把它减少到'2 - 3 n + 3 n^2' – Szabolcs

+0

更简单的是递归定义f [-1] = 2; f [i _]:= 6i + f [i-1 ];' – Timo

+0

像往常一样http://oeis.org/search?q=1%2C2%2C8%2C20%2C38&sort=&language=english&go=Search :) –

3

的部分解决方案,使用图像procssing:

enter image description here

Image /@ ([email protected](ImageData /@ 
    NestList[ 
     Fold[ImageAdd, 
     p = #, (HitMissTransform[p, #, Padding -> 0] & /@ 
      {{{1}, {-1}}, 
      {{-1}, {-1}, {1}}, 
      {{1, -1, -1}}, 
      {{-1, -1, 1}}, 
      {{-1, -1, -1, -1}, {-1, -1, -1, -1}, {1, 1, -1, -1}}, 
      {{-1, -1, -1, 1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}})] &, img, 4])) 

enter image description here

+0

[这个问题](http://dsp.stackexchange.com/q/675/77)会对你感兴趣吗? – abcd

+0

@yoda很好的问题,并不容易。我认为应该尝试识别旋转的椭圆。 –

+0

这会很好,如果你给它一个镜头:)我甚至可以给它提供奖励:D有几个图像处理问题在浮动([这是另一个有趣的问题])(http://dsp.stackexchange.com/问题/ 374 /河流检测在文本)),但没有足够的人知道回答它。很多人只是张贴半被回答的答案... – abcd

4

第一版本:

i = 10; 
a = b = c = Array[0 &, {2 (2 i + 1), 2 (2 i + 1)}]; 
f[n_] := 3*n*(n + 1) + 1; 
k = f[i - 2]; 
p[i_Integer] := 
    [email protected][ 
    -x + y < i - 1 && -x + y > -i + 1 && 
    (2 i + 1 - x)^2 + (2 i + 1 - y)^2 <= 2 i i - 2 && 
    3 i - 1 > x > i + 1 && 
    3 i - 1 > y > i + 1, {x, y}, Integers]; 

((a[[Sequence @@ #]] = 1) & /@ ({x, y} /. {p[i]})); 
((a[[Sequence @@ (# + {2, 2})]] = 0) & /@ ({x, y} /. {p[i - 1]})); 

(b[[Sequence @@ #]] = k--)&/@((# + 2 i {1, 1}) &/@ (SortBy[(# - 2 i {1, 1}) &/@ 
     Position[a, 1], 
     [email protected](Mod[-10^-9 - Pi/4 + ArcTan[Sequence @@ #], 2 Pi]) &])); 
c = Table[b[[2 (2 i + 1) - j, k]], {j, 2 (2 i + 1) - 1}, 
            {k, 2 (2 i + 1) - 1}]; 
MatrixPlot[c] 

enter image description here

编辑

一个更好的:

genMat[m_] := Module[{f, k, k1, i, n, a = {{1}}}, 
    f[n_] := 3*n*(n + 1) + 1; 
    For[n = 1, n <= m, n++, 
    a = ArrayPad[a, 1]; 
    k1 = (f[n - 1] + (k = f[n]) + 2)/2 - 1; 
    For[i = 2, i <= n + 1, i++, a[[i, 2n + 1]] = k--; a[[2-i+2 n, 1]] = k1--]; 
    For[i = n + 2, i <= 2 n + 1, i++, a[[i, 3n+2-i]] = k--; a[[-i,i-n]] = k1--]; 
    For[i = n, i >= 1, i--, a[[2n+1, i]] = k--;a[[1, -i + 2 n + 2]] = k1--]; 
    ]; 
    [email protected][a]; 
    ] 

genMat[5] 
+1

这看起来很有趣;你能解释一下吗? –

+1

@Mr。目前的代码化身仍然过于复杂。只要有空闲时间,我会立即清理并发表评论。这里有两个主要思想(没有什么明显的):1)用几何形状描述“六边形”,让Reduce []找到边,2)按照从多边形中心对角的角度对边元素进行排序。第三个想法不是我的f [n_]:= 3 * n *(n + 1)+ 1来自https://oeis.org/search?q=crystal+ball&language=english&go=Search –

+0

我无法想象这个效率很高,但采用完全不同的方法+1。 –