Board logo

標題: [發問] 在方陣或矩陣中,以旋轉方式填入值 [打印本頁]

作者: 准提部林    時間: 2015-10-24 17:21     標題: 在方陣或矩陣中,以旋轉方式填入值

本帖最後由 准提部林 於 2015-10-27 14:50 編輯

在方陣或矩陣中,以旋轉方式填入值

1.設一個方陣或矩陣為5*5(須考慮可能改變為7*7,9*9...)。
2.任選一個儲存格為〔中心點〕,以此中心點依〔順時針〕方向,〔由內而外〕填入值。

需求效果1:          需求效果2:
[attach]22242[/attach]    [attach]22243[/attach]
 
尋求VBA任何解法,
個人只會〔四輪定位〕法,為避免大家有先入為主的看法,暫不提供程式碼;

希望路過大大不吝提供更多方法,
先此謝過∼∼
 
===2015.10.27 補充===================
程式碼請見14∼16樓,
以非專業自學者而言,只會用最基本的儲存格判斷,所以對初學者也應容易看懂,

而其它大大的程式碼,實為正規的解法,更有參考價值,
再度謝謝各位參與的大大們∼∼

附件下載:
[attach]22255[/attach]
 
作者: ML089    時間: 2015-10-24 22:45

  1. Option Base 1
  2. Sub 以旋轉方式填入值()

  3.     xc = 10: yc = 10 '中心位置

  4.     右 = [{0, 1}]: 下 = [{1,0}]: 左 = [{0,-1}]: 上 = [{-1, 0}]
  5.     yx = Application.Transpose(Application.Transpose(Array(右, 下, 左, 上))) '控制方向及轉向
  6.    
  7.     n = InputBox("輸入排列數字", , 25)
  8.     n1 = Application.RoundUp(((n ^ 0.5) - 1) / 2, 0) + 1
  9.     nn = n1 * 2 + 1
  10.     Cells(yc - n1, xc - n1).Resize(nn, nn).ClearContents

  11.     x = xc: y = yc
  12.     Cells(xc, yc) = 1
  13.     For i = 2 To n
  14.         ds = [{0,0,0,0}]
  15.         For j = 1 To 4 '四個方向
  16.             If Cells(y + yx(j, 1), x + yx(j, 2)) = "" Then
  17.                 ds(j) = ((y + yx(j, 1) - yc) ^ 2 + (x + yx(j, 2) - xc) ^ 2) * 10 + j '距離*10+方向
  18.             Else
  19.                 ds(j) = ""
  20.             End If
  21.         Next
  22.         jj = Application.Min(ds) Mod 10 '取距離原點最短及排列最前方向
  23.         x = x + yx(jj, 2)
  24.         y = y + yx(jj, 1)
  25.         Cells(y, x) = i
  26.     Next
  27. End Sub
複製代碼

作者: 准提部林    時間: 2015-10-24 23:42

回復 2# ML089


就是佩服板主的數學功力!
這題是之前知識+解過的問題,覺得數學太複雜,根本想不出這個方法,只能純粹以Range方法去跑∼∼
謝謝板主的給力∼∼
作者: ML089    時間: 2015-10-25 09:06

回復 3# 准提部林

知識+的W大用數學及函數的功力真是無人能敵,原先一開始我也是朝這方向構想。

後來看你貼的效果圖在哪裡轉啊轉啊,突然想到既然要用VBA就有全新的構想。
從貼圖的運動模式可以整理如下
1. 每一步只有 上、下、左、右 等4種步法
2. 要圍繞中心排列,所以每一步都要選擇離中心最近的距離。

'控制方向及轉向  
yx = Application.Transpose(Application.Transpose(Array(右, 下, 左, 上))) '第一步向右,順時排列
[attach]22244[/attach]
利用上式中 ... 右, 下, 左, 上 的放置順序來控制方向及轉向
第1位置控制第一步方向,可以放置 ..... 右, 下, 左, 上 .... 來改變。
第2~3位置控制順、逆排列方向。

yx = Application.Transpose(Application.Transpose(Array(下, 右, 上, 左)))  '第一步向下,逆時排列
[attach]22245[/attach]

只能寫些簡單VBA,介面及語法有不足的地方歡迎大家繼續修改。
作者: no3-taco    時間: 2015-10-25 19:25

本帖最後由 no3-taco 於 2015-10-25 19:34 編輯

沒有寫得很精實,但是結果是一樣的
ps:需先點選一個足夠填滿的儲存格
  1. Sub testarr()  '從這裡執行
  2. arrX 7, 1  '7階 ,數列初始值
  3. End Sub

  4. Sub arrX(numX&, k&)
  5. Dim cx&, cy&
  6. arr = Array(0, 1, 0, -1, 0, 1)
  7. If numX <> 1 Then
  8. arrX numX - 2, k
  9.     p = (numX - 1) / 2
  10.     For i = 1 To 4
  11.         For j = 0 To numX - 2
  12.             k = k + 1
  13.             cx = ActiveCell.Row + p * arr(i - 1) + arr(i) * j - arr(i) * (p - 1)
  14.             cy = ActiveCell.Column + p * arr(i) + arr(i + 1) * j - arr(i + 1) * (p - 1)
  15.             Cells(cx, cy) = k
  16.         Next j
  17.     Next i
  18.     p = p + 1
  19. Else
  20.     ActiveCell = k
  21. End If
  22. End Sub
複製代碼

作者: 准提部林    時間: 2015-10-25 20:11

回復 5# no3-taco


這是我完全不可能去想的方式, 真是 老手 + 高手,
測試完全符合,
謝謝您的參與及提供知識結晶~~
作者: no3-taco    時間: 2015-10-25 20:26

回復 6# 准提部林

p = p + 1 '修改時忘記拿掉

我不是老手,只是剛剛練習寫正好有寫出來
作者: 准提部林    時間: 2015-10-25 20:41

回復 7# no3-taco


∼∼只是剛剛練習寫〔正好〕有寫出來∼∼ 

那就更不簡單,我是腦神經快轉不過來了!
這題本以為不會有人關注,沒想到還是得到兩個不同解法,真是感激您們的關注!
繼續期待其它解法!!

需求結果2也可再想想∼∼
作者: bobomi    時間: 2015-10-25 22:20

本帖最後由 bobomi 於 2015-10-25 22:27 編輯

Sub q77()

  Cells.Clear
   
'**** 上、下、左、右  copy from  ML089 ****
  右 = [{0, 1, "→","┌"}]: 下 = [{1,0,"↓","┐"}]: 左 = [{0,-1,"←","┘"}]: 上 = [{-1, 0,"↑","└"}]
  
  yx = Array(右, 下, 左, 上)

  r = 10
  c = 10
  Value = 1
  Cells(r, c) = Value
  For Count = 1 To  6^2
  rc = yx(方向 Mod 4)
  n = CLng(Count / 2 + 0.001)
  For Repeat = 1 To n
      r = r + rc(1)
      c = c + rc(2)
      Value = Value + 1
      If Repeat = n Then
         Cells(r, c) = yx((方向 + 1) Mod 4)(4) & " " & Value
      Else
         Cells(r, c) = rc(3) & " " & Value
      End If
  Next
  方向 = 方向 + 1
  Next


' 最後 ◎ ● 這2符號請自己處理

End Sub
作者: ML089    時間: 2015-10-26 12:14

回復 9# bobomi

加入 bobomi 的
右 = [{0, 1, "→","┌"}]: 下 = [{1,0,"↓","┐"}]: 左 = [{0,-1,"←","┘"}]: 上 = [{-1, 0,"↑","└"}]
效果圖二就出來了

Option Base 1
Sub 以旋轉方式填入值()

    xc = 10: yc = 10    '中心位置

    右 = [{0, 1, "→","┌"}]: 下 = [{1,0,"↓","┐"}]: 左 = [{0,-1,"←","┘"}]: 上 = [{-1, 0,"↑","└"}]
    yx = Array(右, 下, 左, 上)    '控制方向及順時轉向

    '    右 = [{0, 1, "→","└"}]: 下 = [{1,0,"↓","┌"}]: 左 = [{0,-1,"←","┐"}]: 上 = [{-1, 0,"↑","┘"}]
    '    yx = Array(下, 右, 上, 左)    '控制方向及逆時轉向

    n = InputBox("輸入排列數字", , 25)
    [A1:Z26].ClearContents

    x = xc: y = yc: xp1 = x: yp1 = y
    Cells(x, y) = 1
    f1 = "": f2 = ""
    For i = 2 To n
        ds = [{"","","",""}]
        For j = 1 To 4    '四個方向
            yy = yx(j)(1): xx = yx(j)(2)
            If Cells(y + yy, x + xx) = "" Then
                ds(j) = ((y + yy - yc) ^ 2 + (x + xx - xc) ^ 2) * 10 + j    '距離*10+方向
            End If
        Next
        k = Application.Min(ds) Mod 10    '取距離原點最短及排列最前方向

        y = y + yx(k)(1)
        x = x + yx(k)(2)
        Cells(y, x) = i

        方向符號 = IIf(i = 2, "◎", yx(k)(3 + IIf(k = kp1, 0, 1)))
        Cells(yp1, xp1) = Cells(yp1, xp1) & 方向符號
        yp1 = y: xp1 = x: kp1 = k

        'Application.Wait TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 1)
    Next
    Cells(yp1, xp1) = Cells(yp1, xp1) & "●"
End Sub
作者: GBKEE    時間: 2015-10-26 16:03

回復 1# 准提部林
Sub 以旋轉方式填入值() 局限在[A1:Z26]
  1. Sub testarr()
  2. arrX 7, 1  '2003 '階數須是奇數,如偶數執行有堆疊空間不足的錯誤
  3. End Sub
複製代碼
Sub Ex()
    '矩陣可為5*5,6*6,7*7,..256*256...視Excel版本
    Dim xNo As Double, Rng As Range, Rc As Double, i As Integer
    ActiveSheet.UsedRange.Clear
    xNo = Application.InputBox("輸入排列數字", , 25, Type:=1)
    Rc = Application.Evaluate("CEILING(Sqrt(" & xNo & "),1)")
    If Rc Mod 2 <> 0 Then i = 1
    If Int(Rc / 2) + i > Int(Columns.Count / 2) Then
       MsgBox "輸入排列數字" & xNo & "的欄位數 " & Int(Rc / 2) + i & vbLf & "大於 工作表之總欄位/ 2  =>" & Columns.Count / 2
       End
    End If
    Set Rng = Cells(Int(Rc / 2) + i, Int(Rc / 2) + i)   '以A1為相對位置的中心儲存格
    Rng.Select
    Rng.Interior.Color = vbRed
    Rng = 1
    Do
        '右,下,左,上 順時鐘方向
        Do
            If Rng >= Rc * Rc Then End
            Rng.Offset(, 1) = Rng + 1
            Set Rng = Rng.Offset(, 1)   '右移一欄
        Loop Until Rng.Offset(1) = ""   '下一列 = ""
        
        Do
            Rng.Offset(1) = Rng + 1
            Set Rng = Rng.Offset(1)      '下移一列
        Loop Until Rng.Offset(, -1) = "" '左一欄 = ""
   
        Do
            If Rng >= Rc * Rc Then End
            Rng.Offset(, -1) = Rng + 1
            Set Rng = Rng.Offset(, -1)  '左移一欄
        Loop Until Rng.Offset(-1) = ""  '上一列 = ""
   
        Do
            Rng.Offset(-1) = Rng + 1
            Set Rng = Rng.Offset(-1)    '上移一列
        Loop Until Rng.Offset(, 1) = "" '右一欄 = ""
    Loop
   
End Sub
作者: no3-taco    時間: 2015-10-26 17:02

回復 8# 准提部林

沒有寫得很好,一開始就只考慮到對稱性
但是還是有符合題目需求,貼上來讓大家指導順便修正哪裡還有問題
  1. Sub testarrX2()  '這裡執行
  2. Cells.Clear
  3. Dim n&: n = 15        '只能奇數
  4. Cells(11, 8).Select    '=>足夠填充的位置
  5. arrX2 n, n, 0         '奇數方陣 ,固定值 ,(0=>符號表式,大於0數字=>序列表示)
  6. End Sub

  7. Sub arrX2(numX&, n&, k&)
  8. Dim cx&, cy&, arr, arr2, arr3
  9. arr = Array(0, 1, 0, -1, 0, 1)
  10. arr2 = Array("┐", "┘", "└", "┌", "●")
  11. arr3 = Array("", "↓", "←", "↑", "→")

  12. If numX <> 1 Then
  13.     arrX2 numX - 2, n, k
  14.     p = (numX - 1) / 2  '(增量)位移量
  15.     For i = 1 To 4
  16.         For j = 0 To numX - 2   
  17.             cx = ActiveCell.Column + p * arr(i) + arr(i + 1) * (j - p + 1)
  18.             cy = ActiveCell.Row + p * arr(i - 1) + arr(i) * (j - p + 1)
  19.             If k = 0 Then
  20.                 If i = 1 And j = 0 Then
  21.                     Cells(cy, cx) = arr2(0)
  22.                 ElseIf i < 4 And j = numX - 2 Then
  23.                     Cells(cy, cx) = arr2(i)
  24.                 ElseIf j = numX - 2 And numX = n Then
  25.                     Cells(cy, cx) = arr2(i)
  26.                 Else
  27.                     Cells(cy, cx) = arr3(i)
  28.                 End If
  29.             Else
  30.                 k = k + 1
  31.                 Cells(cy, cx) = k
  32.             End If
  33.         Next j
  34.     Next i
  35. Else
  36.     ActiveCell = IIf(k > 0, k, "◎")
  37. End If
  38. End Sub
複製代碼

作者: 准提部林    時間: 2015-10-26 18:05

回復 9# bobomi

謝謝提供精心之作,
也謝謝特來參與, 感恩~~
作者: 准提部林    時間: 2015-10-27 14:39

只會基本的Range判定方法,以下程式碼供參考,
對初學VBA者應很容易看得懂:
<四輪定位法>
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
 
Sub 數字矩陣_四輪定位法()
Dim N, xR As Range, M(1 To 4) As Range, C%, R%, X%, Y%
N = InputBox("請輸入方陣欄列數", , 11)
Cells.ClearContents
Set xR = Cells(N / 2 + 2, N / 2 + 2): Set M(1) = xR(2)
For i = 2 To 4: Set M(i) = xR: Next
R = 1: C = 2
For j = 1 To N * N
  xR = j: Set xR = xR(R, C): X = xR.Row: Y = xR.Column
  If X < M(1).Row And Y > M(1).Column Then R = 2: C = 1: Set M(1) = xR
  If X > M(2).Row And Y > M(2).Column Then R = 1: C = 0: Set M(2) = xR
  If X > M(3).Row And Y < M(3).Column Then R = 0: C = 1: Set M(3) = xR
  If X < M(4).Row And Y < M(4).Column Then R = 1: C = 2: Set M(4) = xR
  Sleep 10
101: Next
End Sub

'===================================
Sub 方向矩陣_四輪定位法()
Dim N, xR As Range, M(1 To 4) As Range, C%, R%, X%, Y%, T$
N = InputBox("請輸入方陣欄列數", , 11)
Cells.ClearContents
Set xR = Cells(N / 2 + 2, N / 2 + 2): Set M(1) = xR(2)
For i = 2 To 4: Set M(i) = xR: Next
R = 1: C = 2: T = "◎"
For j = 1 To N * N - 1
  If xR = "" Then xR = T
  Set xR = xR(R, C): X = xR.Row: Y = xR.Column
  If X < M(1).Row And Y > M(1).Column Then R = 2: C = 1: T = "↓": Set M(1) = xR: xR = "┐"
  If X > M(2).Row And Y > M(2).Column Then R = 1: C = 0: T = "←": Set M(2) = xR: xR = "┘"
  If X > M(3).Row And Y < M(3).Column Then R = 0: C = 1: T = "↑": Set M(3) = xR: xR = "└"
  If X < M(4).Row And Y < M(4).Column Then R = 1: C = 2: T = "→": Set M(4) = xR: xR = "┌"
  Sleep 10
101: Next
xR = "●"
End Sub
作者: 准提部林    時間: 2015-10-27 14:40

<牆角摸索法>
Sub 數字矩陣_牆角摸索法()
Dim i&, xR As Range, R&, C&, N
N = InputBox("輸入欄列數", , 11)
Cells.ClearContents
Set xR = Cells(N / 2 + 2, N / 2 + 2): xR = 1: Set xR = xR(1, 2)
For i = 2 To N * N
  If xR(1, 0) <> "" And xR(2, 1) = "" Then R = 2: C = 1
  If xR(0, 1) <> "" And xR(1, 0) = "" Then R = 1: C = 0
  If xR(1, 2) <> "" And xR(0, 1) = "" Then R = 0: C = 1
  If xR(2, 1) <> "" And xR(1, 2) = "" Then R = 1: C = 2
  xR = i:  Set xR = xR(R, C)
  Sleep 10
Next i
End Sub
 
'====================================
Sub 方向矩陣_牆角摸索法()
Dim i&, xR As Range, R&, C&, T$, N
N = InputBox("輸入欄列數", , 11)
Cells.ClearContents
Set xR = Cells(N / 2 + 2, N / 2 + 2):  xR = "◎":  Set xR = xR(1, 2)
For i = 2 To N * N - 1
    If xR(1, 0) <> "" And xR(2, 1) = "" And xR(0, 1) = "" Then R = 2: C = 1: xR = "┐": T = "↓"
    If xR(0, 1) <> "" And xR(1, 0) = "" And xR(1, 2) = "" Then R = 1: C = 0: xR = "┘": T = "←"
    If xR(1, 2) <> "" And xR(0, 1) = "" And xR(2, 1) = "" Then R = 0: C = 1: xR = "└": T = "↑"
    If xR(2, 1) <> "" And xR(1, 2) = "" And xR(1, 0) = "" Then R = 1: C = 2: xR = "┌": T = "→"
    If xR = "" Then xR = T
    Set xR = xR(R, C)
    Sleep 10
Next i
xR = "●"
End Sub
作者: 准提部林    時間: 2015-10-27 14:41

<十字非空檢查法>
Sub 數字矩陣_十字非空檢查法()
Dim i&, xR As Range, R&, C&, N, j&, k&
N = InputBox("輸入欄列數", , 11)
Cells.ClearContents
Set xR = Cells(N / 2 + 2, N / 2 + 2): xR = 1: Set xR = xR(1, 2)
For i = 2 To N * N
  For j = 1 To 4
    If xR(0, 0).Resize(3, 3).Item(j * 2) <> "" Then k = k & j
  Next j
  If k < 5 Then R = Mid("1201", k, 1): C = Mid("0112", k, 1)
  xR = i:  Set xR = xR(R, C): k = 0
  Sleep 10
Next i
End Sub
 
'====================================
Sub 方向矩陣_十字非空檢查法()
Dim i&, xR As Range, R&, C&, N, j&, k&, T$
N = InputBox("輸入欄列數", , 11)
Cells.ClearContents
Set xR = Cells(N / 2 + 2, N / 2 + 2): xR = "◎": Set xR = xR(1, 2)
For i = 2 To N * N - 1
  For j = 1 To 4
    If xR(0, 0).Resize(3, 3).Item(j * 2) <> "" Then k = k & j
  Next j
  If k < 5 Then
    R = Mid("1201", k, 1): C = Mid("0112", k, 1)
    T = Mid("←↓↑→", k, 1): xR = Mid("┘┐└┌", k, 1)
  End If
  If xR = "" Then xR = T
  Set xR = xR(R, C): k = 0
  Sleep 10
Next i
xR = "●"
End Sub
作者: n7822123    時間: 2015-10-30 11:23

回復 1# 准提部林

不知道現在回會不會太晚~
我用很直覺的寫法,走到底就轉彎~
  1. Sub 方陣1()
  2. Dim 邊界 As Byte
  3. Dim 邊 As Byte
  4. Dim X0 As Byte
  5. Dim Y0 As Byte
  6. Dim n As Integer
  7. Cells(5, 5).CurrentRegion = ""
  8. 邊界 = (Cells(1, 2) - 1) / 2
  9. X0 = 邊界 + 5: Y0 = 邊界 + 5
  10. n = 1: X = X0: Y = Y0: 邊 = 1
  11. Cells(Y, X) = n: n = n + 1
  12. 向右:
  13. If n = (邊 * 2 + 1) ^ 2 And 邊 < 邊界 Then 邊 = 邊 + 1
  14. If n = (邊 * 2 + 1) ^ 2 And 邊 = 邊界 Then GoTo 結尾
  15. If X + 1 - X0 > 邊 Then GoTo 向下
  16. X = X + 1: Cells(Y, X) = n: n = n + 1: GoTo 向右
  17. 向下:
  18. If Y + 1 - Y0 > 邊 Then GoTo 向左
  19. Y = Y + 1: Cells(Y, X) = n: n = n + 1: GoTo 向下
  20. 向左:
  21. If X - 1 - X0 < -邊 Then GoTo 向上
  22. X = X - 1: Cells(Y, X) = n: n = n + 1: GoTo 向左
  23. 向上:
  24. If Y - 1 - Y0 < -邊 Then GoTo 向右
  25. Y = Y - 1: Cells(Y, X) = n: n = n + 1: GoTo 向上
  26. 結尾:
  27. X = X + 1: Cells(Y, X) = n
  28. End Sub

  29. Sub 方陣2()
  30. Dim 邊界 As Byte
  31. Dim 邊 As Byte
  32. Dim X0 As Byte
  33. Dim Y0 As Byte
  34. Dim n As Integer
  35. Cells(5, 5).CurrentRegion = ""
  36. 邊界 = (Cells(1, 2) - 1) / 2
  37. X0 = 邊界 + 5: Y0 = 邊界 + 5
  38. n = 1: X = X0: Y = Y0: 邊 = 1
  39. Cells(Y, X) = "◎": n = n + 1
  40. 向右:
  41. If n = (邊 * 2 + 1) ^ 2 And 邊 < 邊界 Then 邊 = 邊 + 1
  42. If n = (邊 * 2 + 1) ^ 2 And 邊 = 邊界 Then GoTo 結尾
  43. If X + 1 - X0 > 邊 Then GoTo 向下
  44. X = X + 1
  45. If X - X0 = 邊 Then Cells(Y, X) = "┐" Else Cells(Y, X) = "→"
  46. n = n + 1: GoTo 向右
  47. 向下:
  48. If Y + 1 - Y0 > 邊 Then GoTo 向左
  49. Y = Y + 1
  50. If Y - Y0 = 邊 Then Cells(Y, X) = "┘" Else Cells(Y, X) = "↓"
  51. n = n + 1: GoTo 向下
  52. 向左:
  53. If X - 1 - X0 < -邊 Then GoTo 向上
  54. X = X - 1
  55. If X - X0 = -邊 Then Cells(Y, X) = "└" Else Cells(Y, X) = "←"
  56. n = n + 1: GoTo 向左
  57. 向上:
  58. If Y - 1 - Y0 < -邊 Then GoTo 向右
  59. Y = Y - 1
  60. If Y - Y0 = -邊 Then Cells(Y, X) = "┌" Else Cells(Y, X) = "↑"
  61. n = n + 1: GoTo 向上
  62. 結尾:
  63. X = X + 1: Cells(Y, X) = "●"
  64. End Sub
複製代碼

作者: 准提部林    時間: 2015-10-30 13:30

回復 17# n7822123


這題目的是看不同的解法, 集思廣義!
貴解測試完全可用, 謝謝參與!




歡迎光臨 麻辣家族討論版版 (http://forum.twbts.com/)