這是我大學程式設計課上的題目,最近整理電腦時被我挖出來,自己又重新做了一次,覺得蠻有趣的,給大家動動腦。
題目說明:
矩陣大小 SIZE 需可由變數或 #define 控制,範圍 1 <= SIZE <= 9。
蛇行:
螺旋:
魔方陣:
程式碼如下:
蛇行:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
int main(void)
{
int x, y;
int array[SIZE][SIZE] = {0};
for (int i = 0; i < SIZE * SIZE; i++)
{
x = i / SIZE;
//奇數列由小到大,偶數列由大到小
y = x % 2 == 0 ? i % SIZE : SIZE - 1 - i % SIZE;
array[x][y] = i + 1;
}
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
printf("%2d ", array[i][j]);
}
printf("\n");
}
system("pause");
return 0;
}
螺旋:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
//走法偏移量: 右->下->左->上
int dir_x[4] = {0, 1, 0, -1};
int dir_y[4] = {1, 0, -1, 0};
int main(void)
{
int index, x, y, temp_x, temp_y;
int array[SIZE][SIZE] = {0};
index = 0;
x = 0;
y = -1;
for (int i = 0; i < SIZE * SIZE; i++)
{
//試走,如果超出邊界或遇到已經走過的格子,index + 1 轉彎
temp_x = x + dir_x[index];
temp_y = y + dir_y[index];
if (temp_x < 0 || temp_x > SIZE - 1 ||
temp_y < 0 || temp_y > SIZE - 1 ||
array[temp_x][temp_y] != 0)
{
index = (index + 1) % 4;
}
//往下一個座標前進
x = x + dir_x[index];
y = y + dir_y[index];
array[x][y] = i + 1;
}
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
printf("%2d ", array[i][j]);
}
printf("\n");
}
system("pause");
return 0;
}
魔方陣:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
int main(void)
{
int x, y;
int array[SIZE][SIZE] = {0};
x = 0;
y = SIZE / 2;
for (int i = 0; i < SIZE * SIZE; i++)
{
//如果超過斜對角,左下往右上的最後一格,或遇到已經走過的格子,就退回並往下
if ((x < 0 && y > SIZE - 1) ||
(x >= 0 && y <= SIZE - 1 && array[x][y] != 0))
{
x = x + 2;
y = y - 1;
}
//超過邊界就將該軸座標移動到對面
x = (x + SIZE) % SIZE;
y = y % SIZE;
array[x][y] = i + 1;
//往右上前進
x = x - 1;
y = y + 1;
}
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
printf("%2d ", array[i][j]);
}
printf("\n");
}
system("pause");
return 0;
}
我來贊助一個 Excel VBA 的版本
改了一點地方
1.最大值不限於 9
2.蛇行與螺旋的陣列可以不是正方形(eg.3x5, 7x9...)
3.三個題目用類似的方法解
Option Explicit
Const kMATRIX_TYPE_SNAKE = 1
Const kMATRIX_TYPE_SPIRAL = 2
Const kMATRIX_TYPE_MAGIC = 3
Const kDIRECTION_RIGHT_DOWN_LEFT = 1
Const kDIRECTION_RIGHT_DOWN_DOWN = 2
Const kDIRECTION_LEFT_DOWN = 3
Const kDIRECTION_DOWN_LEFT = 4
Const kDIRECTION_LEFT_UP = 5
Const kDIRECTION_UP_RIGHT = 6
Const kDIRECTION_MAGIC = 7
Sub Main()
Range("A1:AD40").Clear
Call MatrixFiller(kMATRIX_TYPE_MAGIC, 11, 11)
MsgBox "Done", vbInformation
End Sub
Sub MatrixFiller(matrixtype, maxrow, maxcol)
'=============================================================
'參數說明:
'matrixtype : SNAKE, SPIRAL, MAGIC 三種
'maxrow : 列數
'maxcol : 行數
'
'SNAKE, SPIRAL 的 maxrow, maxcol 為大於 0 整數即可
'MAGIC 的 maxrow, maxcol 均須為大於 0 單數且兩者必須相同
'=============================================================
On Error GoTo ErrorOutOfBound
Dim iLoop As Integer
Dim direction
Dim cellNow As Range
Dim bOutOfBound As Boolean
'============================
'Init Values
'============================
bOutOfBound = False
Select Case matrixtype
Case kMATRIX_TYPE_SNAKE
Range("A1").Offset(0, 0).Select
direction = kDIRECTION_RIGHT_DOWN_LEFT
Case kMATRIX_TYPE_SPIRAL
Range("A1").Offset(0, 0).Select
direction = kDIRECTION_RIGHT_DOWN_DOWN
Case kMATRIX_TYPE_MAGIC
If (maxrow <> maxcol) Or (Int(maxrow / 2) = (maxrow / 2)) Or (Int(maxcol / 2) = (maxcol / 2)) Then
MsgBox "無法計算", vbCritical
Exit Sub
End If
Range("A1").Offset(0, (maxcol - 1) / 2).Select
direction = kDIRECTION_MAGIC
End Select
ActiveCell.Value = 1
'============================
'Main Loop
'============================
For iLoop = 2 To maxrow * maxcol
bOutOfBound = False
Select Case direction
Case kDIRECTION_RIGHT_DOWN_LEFT '往右,碰壁往下後, 接著住左
If ActiveCell.Offset(0, 1).Column > maxcol Then
ActiveCell.Offset(1, 0).Select
direction = kDIRECTION_LEFT_DOWN
Else
ActiveCell.Offset(0, 1).Select
End If
ActiveCell.Value = iLoop
Case kDIRECTION_LEFT_DOWN '往左,碰壁往下
ActiveCell.Offset(0, -1).Select
If bOutOfBound = True Then
ActiveCell.Offset(1, 0).Select
direction = kDIRECTION_RIGHT_DOWN_LEFT
End If
Case kDIRECTION_RIGHT_DOWN_DOWN '往右,碰壁往下後, 接著往下
If ((ActiveCell.Offset(0, 1).Column > maxcol) Or (IsEmpty(ActiveCell.Offset(0, 1).Value)) = False) Then
ActiveCell.Offset(1, 0).Select
direction = kDIRECTION_DOWN_LEFT
Else
ActiveCell.Offset(0, 1).Select
End If
Case kDIRECTION_DOWN_LEFT '往下,碰壁往左
If (ActiveCell.Offset(1, 0).Row > maxrow) Or (IsEmpty(ActiveCell.Offset(1, 0).Value) = False) Then
ActiveCell.Offset(0, -1).Select
direction = kDIRECTION_LEFT_UP
Else
ActiveCell.Offset(1, 0).Select
End If
Case kDIRECTION_LEFT_UP '往左,碰壁往上
ActiveCell.Offset(0, -1).Select
If bOutOfBound = True Then
ActiveCell.Offset(-1, 0).Select
direction = kDIRECTION_UP_RIGHT
Else
If (IsEmpty(ActiveCell.Value) = False) Then
ActiveCell.Offset(-1, 1).Select
direction = kDIRECTION_UP_RIGHT
End If
End If
Case kDIRECTION_UP_RIGHT '往上,碰壁往右
If IsEmpty(ActiveCell.Offset(-1, 0).Value) Then
ActiveCell.Offset(-1, 0).Select
Else
ActiveCell.Offset(0, 1).Select
direction = kDIRECTION_RIGHT_DOWN_DOWN
End If
Case kDIRECTION_MAGIC '往右上, 以及魔方陣的移動邏輯
ActiveCell.Offset(-1, 1).Select
If bOutOfBound = True Then '出界, 有三種情形
If ((ActiveCell.Column = maxcol) And (ActiveCell.Row = 1)) Then '在最右上角出界
ActiveCell.Offset(1, 0).Select
ElseIf (ActiveCell.Row = 1) Then '在最上面出界
ActiveCell.Offset(maxrow - 1, 1).Select
End If
Else
If (ActiveCell.Column > maxcol) Then '在最右邊出界
ActiveCell.Offset(0, -1 * maxcol).Select
Else
If (IsEmpty(ActiveCell.Value) = False) Then '如果已經有值, 就移動到自己的下方
ActiveCell.Offset(2, -1).Select
End If
End If
End If
End Select
ActiveCell.Value = iLoop
Next
Exit Sub
ErrorOutOfBound:
bOutOfBound = True
Resume Next
End Sub
感謝海綿寶寶大大的分享,
透過 direction 靈活的控制行走方向,
透過 bOutOfBound 漂亮的處理出界,一開始還看不懂用法,
Google 後才發現原來有 Resume Next 這種寫法,
又學到了一課 XD
Resume Next 倒是還好
有點像有些語言裡的 try/catch/finally
你沒提到的是
我這個幾十歲的人了
居然還在用 GOTO 指令(On Error Goto)
您不說我還沒發現,
一開始以為 ErrorOutOfBound 像 catch(ErrorOutOfBound ex),
原來不是,是 GoTo 的標記阿,
出錯會先跳到 On Error,
然後 GoTo 到 ErrorOutOfBound,
然後再 Resume Next 到出錯的下一行,
雖然大家都不建議使用 GoTo,但大大使用一定有深意 XD
有時候解一些題目來鍛鍊邏輯還滿有趣的,
我朋友也有提供一個解演算法的網站,
不過我都沒時間上去玩,哈哈
https://leetcode.com/
進去後直接左上繳的problem
感謝大大分享,
這個網站我知道,不過小弟對英文有障礙,所以比較常做中文題