图是要求的输出范例
程序要求输入一个大于等于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模拟随机随访。(当然这应该不是题者本意)