我想通过以下方式填充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 _ _ _
使用 Mathematica 进行此操作的简单方法是什么?
答案 0 :(得分:12)
使用此辅助函数:
Clear[makeSteps];
makeSteps[0] = {};
makeSteps[m_Integer?Positive] :=
Most@Flatten[
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
。
答案 1 :(得分: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)
我很确定有一个更简单的算法,但对我来说这是最直观的算法。
答案 2 :(得分:4)
从1开始向上的对角线上的幻数可以从
到达f[n_] := 2 Sum[2 m - 1, {m, 1, n}] + UnitStep[n - 3] Sum[2 m, {m, 1, n - 2}]
In := f@Range@5
Out := {2, 8, 20, 38, 62}
有了这个,设置SparseArray
应该很容易。我会玩一下它,看看有多难。
答案 3 :(得分: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] :=
ToRules@Reduce[
-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],
N@(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]
修改强>
更好的一个:
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--];
];
Return@MatrixForm[a];
]
genMat[5]
答案 4 :(得分:3)
部分解决方案,使用图像处理:
Image /@ (Differences@(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]))