蛇形矩阵 php,C语言输出特殊N*N蛇形矩阵?

bVKRcH?w=495&h=909

图是要求的输出范例

程序要求输入一个大于等于5的奇数n

然后输出一个和示例图类似的特殊蛇形矩阵 中心是0然后向外展开

要求是不能用数组和stdio.h以外的lib

已经想了整整一下午了 完全没有任何思路.

求大神帮帮忙想一下思路,不用写代码,帮忙想想思路就行.

P.S. 若覺得我的答案不佳或是有誤還請不吝指教, 光是給負分無法讓答案精進, 謝謝

改寫了代碼, 不使用數組

思路:

最大的關鍵是找出規則, 首先我們來算出 n 階蛇行矩陣要使用多少的 digit (from 0-9):

我們觀察規則:

(示意圖) 5 階蛇行矩陣需要使用 5+4+4+2+2 個數字

5

----->

65432

^  ----1  |

2 |  210-0  | 4

|  3---9  |

45678  |

v

<----

4

5*5 矩陣共填入 5+4+4+2+2 個數字

5: first row 右行

4: last col 下行

4: last row 左行

2: first col 上行

2: third row 右行

7*7 矩陣共填入 7+6+6+4+4+2+2 個數字

導出:

total

= n + 2*(n-1-2*0) + 2*(n-1-2*1) + ... 2*(n-1-2*((n-1)/2-1))

(中間的級數運算就省略)

= (n^2+2n-1)/2 個數字

比如說我們得出 5 階矩陣要填入 17 個數字, 那

0, 0

位置要填入的值為第 16 個數字(從 0 開始算):

65432109876543210

^               ^

第 16 個數字     第 0 個數字

16%10 = 6

所以說 n 階矩陣的第

c

個數字的值為:

c%10

有了上述認知之後, 我們來討論如何找出矩陣中

i, j

位置的元素是第幾個要填入的值, 方法很簡單, 我們試著從頭開始繞行, 等到繞行到該位置時去檢查這是輪到第幾個應填入的數字

模擬繞行的過程可以簡單表示為:

首先算出應填入數字數量

C

, 我們繞行時會從第

C-1

個數字開始填從 first row 開始向右行走 n 個位置, 每個位置分別對應前 n 個應填入的數字 (

c = C-1

~

c = C-1-n

)

如果中間有經過位置

i, j

則確認位置

i, j

應填入第

c

個數字, 值為

c%10

如果沒有則需要向右轉開始下行, 設定方向

direction

'down'

, 調整步數

move

為 n-1

direction

方向前進

move

步, 同時要持續計算, 維持每個位置對應的數字

如果中間有經過位置

i, j

則確認位置

i, j

應填入第

c

個數字, 值為

c%10

如果沒有則需要向右轉, 根據現有方向設定

direction

, 調整步數

move

如果是第一次走

move

步, 則維持現有步數

如果是第二次走

move

步, 則調整步數

move

move-2

如果走到最後發現沒有被走到, 則表示該位置應填入

"-"

當我們能夠模擬繞行找出每個位置應填入的值之後, 就可以用兩層迴圈遍歷矩陣中所有位置同時印出個位置的值

代碼:

def turn_right(direction):

if direction=='right':

direction = 'down'

elif direction=='down':

direction = 'left'

elif direction=='left':

direction = 'up'

elif direction=='up':

direction = 'right'

return direction

def goahead(direction, row, col):

if direction=='right':

col += 1

elif direction=='down':

row += 1

elif direction=='left':

col -= 1

elif direction=='up':

row -= 1

return row, col

def compute_position(n, i, j):

"""

Given  size: n, row index: i, col index: j

Return element: digit 0-9 or char "-"

"""

c = (n**2+2*n-1)//2

row = 0

col = -1

move = n

is_first_row = True

direction = 'right'

while move >= 2:

for _i1 in range(1 if is_first_row else 2):

for _i2 in range(move):

c -= 1

row, col = goahead(direction, row, col)

if row==i and col==j:

return (c%10)

direction = turn_right(direction)

move = move - (1 if is_first_row else 2)

is_first_row = False

return '-'

def decimal_spiral(n):

for i in range(n):

for j in range(n):

print(compute_position(n, i, j), end='')

print()

decimal_spiral(7)

輸出:

876543210

--------9

8765432-8

9-----1-7

0-210-0-6

1-3---9-5

2-45678-4

3-------3

456789012

我回答過的問題: Python-QA

可以通过递归实现这个算法。

思路:通过递归计算矩阵中所有坐标处所要输出的字符(递归每层只计算一个位置的字符,从中心开始沿数字路径计算)。在当前坐标为下一个输出位置的坐标时输出。多次递归,完成整个矩阵的输出。(比较粗暴)

#include <stdio.h>

const int size = 9;

const int direction = (size-5)/2%2==0 ? 3 : 1; // 0:up, 1:right, 2:down, 3:left;

const int rotation = 1; // 0:clockwise, 1:counter

typedef struct Position_ {

int r; // row

int c; // col

} Position;

Position print;

inline void check_print(char ch, int r, int c) {

if (r == print.r && c == print.c) {

printf("%c", ch);

print.c++;

if (print.c % size == 0) {

printf("\n");

print.c = 0;

print.r++;

}

}

}

char foo(Position position, Position from, Position before_from, Position direction, char hint,

int step = 0, int step_left = 0, int counter = 0) {

if (position.r < 0 || position.c < 0 ||

position.r >= size || position.c >= size)

return 1;

if (print.r >= size || print.c >= size)

return 0;

check_print(hint, position.r, position.c);

if (hint == '-')

return 1;

if (step_left == 0) {

counter++;

if (rotation == 1) { // counter-clockwise

int temp = direction.r - direction.c;

direction.r = direction.r==0 ? temp : 0;

direction.c = direction.c==0 ? temp : 0;

} else { // clockwise

int temp = direction.c - direction.r;

direction.r = direction.r==0 ? temp : 0;

direction.c = direction.c==0 ? temp : 0;

}

step_left = step;

if (counter%2 == 0) {

step += 2;

step_left = step;

}

}

Position to;

to.r = position.r + direction.r;

to.c = position.c + direction.c;

Position after_direction = direction;

Position after_to = to;

if (step_left-1 == 0) {

if (rotation == 1) { // counter-clockwise

int temp = after_direction.r - after_direction.c;

after_direction.r = after_direction.r==0 ? temp : 0;

after_direction.c = after_direction.c==0 ? temp : 0;

} else { // clockwise

int temp = after_direction.c - after_direction.r;

after_direction.r = after_direction.r==0 ? temp : 0;

after_direction.c = after_direction.c==0 ? temp : 0;

}

}

after_to.r += after_direction.r;

after_to.c += after_direction.c;

for (int i=-1; i<2; ++i) {

for (int j=-1; j<2; ++j) {

Position next;

next.r = position.r + i;

next.c = position.c + j;

if (next.r==to.r && next.c==to.c)

continue;

if (next.r==from.r && next.c==from.c)

continue;

if (next.r==before_from.r && next.c==before_from.c)

continue;

if (next.r == after_to.r && next.c == after_to.c)

continue;

if (foo(next, from, from, direction, '-') == 0)

return 0;

check_print(hint, position.r, position.c);

}

}

char next_hint = (hint-'0'+1)%10 + '0';

if (foo(to, position, from, direction, next_hint, step, step_left-1, counter) == 0)

return 0;

check_print(hint, position.r, position.c);

return 2;

}

int main() {

Position from, to, dir;

if (direction == 0) {

dir.r = -1;

dir.c = 0;

} else if (direction == 1) {

dir.r = 0;

dir.c = 1;

} else if (direction == 2) {

dir.r = 1;

dir.c = 0;

} else {

dir.r = 0;

dir.c = -1;

}

from.r = to.r = (size+1)%4==0 ? (size+1)/2 : size/2;

from.c = to.c = (size+1)%4==0 ? (size-2)/2 : size/2;

print.r = 0;

print.c = 0;

while (foo(to, from, from, dir, '0', 2, 2, 0) != 0) {

}

return 0;

}

已经修正代码的bug。主要问题有两点:没有自动计算起始方向,中心坐标计算错误(你在问题描述中说是中心为0,我误以为是指矩阵的中点)。

这里难点主要在递归。递归从中间的0开始,沿着数字的方向往外走,并在每层发散到相邻非数字的格子(非数格不发散)。hint是当前层的输出,position是当前层输出对应的坐标。from, before_from, to, after_to分别是前一个数字格,再前一个数字格子,下一个数字格,再下一个数字格的坐标。direction是前进方向,step, step_left, counter均用于计算转向的时机。

另:考虑到stdio里有文件流的操作函数,可以直接打开文件,通过fseek模拟随机随访。(当然这应该不是题者本意)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值