iT邦幫忙

4

[C++][動動腦] 特殊矩陣 - 蛇行、螺旋、魔方陣

c++

這是我大學程式設計課上的題目,最近整理電腦時被我挖出來,自己又重新做了一次,覺得蠻有趣的,給大家動動腦。

題目說明:
矩陣大小 SIZE 需可由變數或 #define 控制,範圍 1 <= SIZE <= 9。

蛇行:
https://ithelp.ithome.com.tw/upload/images/20171109/20106865bD8QXr8wnx.jpg

螺旋:
https://ithelp.ithome.com.tw/upload/images/20171109/201068656f1ccSKmjj.jpg

魔方陣:
https://ithelp.ithome.com.tw/upload/images/20171109/20106865QWklUiBXeD.jpg

程式碼如下:

蛇行:

#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;
}

2 則留言

0
海綿寶寶
iT邦超人 1 級 ‧ 2017-11-11 12:53:09

我來贊助一個 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
/images/emoticon/emoticon41.gif

Resume Next 倒是還好
有點像有些語言裡的 try/catch/finally
你沒提到的是
我這個幾十歲的人了
居然還在用 GOTO 指令(On Error Goto)
/images/emoticon/emoticon45.gif

您不說我還沒發現,
一開始以為 ErrorOutOfBound 像 catch(ErrorOutOfBound ex),
原來不是,是 GoTo 的標記阿,
出錯會先跳到 On Error,
然後 GoTo 到 ErrorOutOfBound,
然後再 Resume Next 到出錯的下一行,
雖然大家都不建議使用 GoTo,但大大使用一定有深意 XD

/images/emoticon/emoticon37.gif

0
神Q超人
iT邦新手 5 級 ‧ 2017-11-11 19:42:15

有時候解一些題目來鍛鍊邏輯還滿有趣的,
我朋友也有提供一個解演算法的網站,
不過我都沒時間上去玩,哈哈
https://leetcode.com/
進去後直接左上繳的problem

感謝大大分享,
這個網站我知道,不過小弟對英文有障礙,所以比較常做中文題
/images/emoticon/emoticon02.gif

我要留言

立即登入留言