###### tags: `APCS` `C292` `C` # C292. 數字龍捲風 ## 題目描述 ### 內容 給定一個 N*N 的二維陣列,其中N是奇數,我們可以從正中間的位置開始順 時針旋轉的方式走訪每個陣列元素恰好一次。對於給定的陣列內容與起始方向 ,請輸出走訪順序之內容。下面的例子顯示了N=5且第一步往左的走訪順序: | 3 | 4 | 2 | 1 | 4 | | ---- | ---- | ---- | ---- | ---- | | <b>4 | <b>2 | <b>3 | <b>8 | <b>9 | | <b>2 | <b>1 | <b>9 | <b>5 | <b>6 | | <b>4 | <b>2 | <b>3 | <b>7 | <b>8 | | <b>1 | <b>2 | <b>6 | <b>4 | <b>3 | | → | → | → | → | ↓ | | - | - | - | - | - | | ↑ | → | → | ↓ | ↓ | | ↑ | ↑ | ← | ↓ | ↓ | | ↑ | ← | ← | ← | ↓ | | <b>1 | ← | ← | ← | ← | 依此順序輸出陣列內容則可以得到 「9123857324243421496834621」。 類似地,如果是第一步向上則走訪順序下: | 3 | → | → | → | ↓ | | - | - | - | - | - | | ↑ | ↑ | → | ↓ | ↓ | | ↑ | ↑ | ↑ | ↓ | ↓ | | ↑ | ↑ | ← | ← | ↓ | | ↑ | ← | ← | ← | ← | 依此順序輸出陣列內容則可以得到 「9385732124214968346214243」。 ### 輸入說明 輸入第一行是整數N,N為奇數且不小於3。 第二行是一個0~3的整數代表起始方向,其中0代表左、1代表上、2代表右、3代表下。 第三行開始N行是陣列內容,順序是由上而下、左至右, 陣列的內容為 0~9 的整數,同一行數字中間以一個空白間隔。 ### 輸出說明 輸出走訪順序的陣列內容,該答案會是一連串的陣列內容, 數字之間不要輸出空白,結尾有換行符號。 ### 評分說明 輸入包含若干筆測試資料,每一的執行時間限制(time limit)均為1秒, 依正確通過測資筆數給分。其中: 第1子題組20分,3 ≤ N ≤ 5,且起始方向均為左。 第2子題組80分,3 ≤ N ≤ 49,起始方向無限定。 ### 範例 測資 1: 5 0 3 4 2 1 4 4 2 3 8 9 2 1 9 5 6 4 2 3 7 8 1 2 6 4 3 輸出 1: 9123857324243421496834621 測資 2: 3 1 4 1 2 3 0 5 6 7 8 輸出 2: 012587634 *** ## 題目思索 此為當初發想時的**心智圖**,我嘗試使用學到的遞回解題,一開始先設定好變數行列n、方向dir、二維陣列a、格數layer與次數count,輸入後先將**最中間的數輸出**,再代入迴圈loop中。 ![c292c](https://hackmd.io/_uploads/SJpiQVAmp.png) loop分別有y與x,代表前一數的**y座標**與**x座標**(右下為正),先判斷該座標是否在陣列範圍內,再判斷方向、計數,若dir等於4(從向下改變到向左),則設為0,若計數為2(該層已重複2次),則層數增加、計數設為0。 之後再判斷方向,輸出**同方向移動所經過的所有數**(個數為layer),並更新至移動後的座標,最後將dir加1(順時針轉動),count加1,將新座標代入下一個loop內。 格數與次數解釋:我將觀察到移動格數的變化設為layer(格數)與count(次數),以範例一來看,先從a[2][2]往左移動1格,再往上移動1格,兩次過後,移動的格數變成2格,以此類推,count每增加至2時,則layer將增加1,count將重製。 ### 初稿程式碼 ```c= #include <stdio.h> int a[49][49]; int n = 0, dir; int layer = 1, count = 0; int loop(int y, int x){ int i = 1; if(y < 0 || x < 0 || y == n || x == n) return 0; if(dir == 4) dir = 0; if(count == 2){ layer++; count = 0; } if(dir == 0){ //left for(i = 1; i <= layer; i++) printf("%d", a[y][x - i]); x = x - i + 1; } if(dir == 1){ //up for(i = 1; i <= layer; i++) printf("%d", a[y - i][x]); y = y - i + 1; } if(dir == 2){ //right for(i = 1; i <= layer; i++) printf("%d", a[y][x + i]); x = x + i - 1; } if(dir == 3){ //down for(i = 1; i <= layer; i++) printf("%d", a[y + i][x]); y = y + i - 1; } dir++; count++; loop(y, x); } int main(){ scanf("%d%d", &n, &dir); for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) scanf("%d", &a[i][j]); printf("%d", a[n/2][n/2]); loop(n / 2, n / 2); return 0; } ``` ### 測試結果 ![c292. APCS2017-0304-3數字龍捲風 ](https://hackmd.io/_uploads/rJ5H7rC76.png) ### 嘗試更正 當初的想法並未健全,經測資1、2測試後發現輸出皆多了一個0,往回一看才發現最後一次輸出時,會順勢輸出一個限制座標範圍外的數並以0表示。 為了較快解決此問題,我在最初多宣告了一個變數first,用以儲存最初的dir,以及在迴圈內的判斷dir前多了一個判斷,若dir與first方向相同,且layer與n相同(最後一次)時,格數將少一次。 ```c if(dir == first && layer == n) layer--; ``` 迴圈的最後再補上個判斷,用以分辨是否為最後一次輸出,若是,則return跳出迴圈並結束此程式。 ```c if(dir == first && layer == n-1) return; ``` ### 更正後測試結果 ![c292t](https://hackmd.io/_uploads/Bkve5q14T.png) *** ## 成果 ### 程式碼 ```c= #include <stdio.h> int a[49][49]; int n = 0, dir; int layer = 1, count = 0, first; void loop(int y, int x){ int i = 1; if(y < 0 || x < 0 || y == n || x == n) return; if(dir == 4) dir = 0; if(count == 2){ layer++; count = 0; } if(dir == first && layer == n) layer--; if(dir == 0){ //left for(i = 1; i <= layer; i++) printf("%d", a[y][x - i]); x = x - i + 1; } if(dir == 1){ //up for(i = 1; i <= layer; i++) printf("%d", a[y - i][x]); y = y - i + 1; } if(dir == 2){ //right for(i = 1; i <= layer; i++) printf("%d", a[y][x + i]); x = x + i - 1; } if(dir == 3){ //down for(i = 1; i <= layer; i++) printf("%d", a[y + i][x]); y = y + i - 1; } if(dir == first && layer == n-1) return; dir++; count++; loop(y, x); } int main(){ scanf("%d%d", &n, &dir); first = dir; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) scanf("%d", &a[i][j]); printf("%d", a[n/2][n/2]); loop(n / 2, n / 2); return 0; } ``` ### 解題 ![c292re](https://hackmd.io/_uploads/HkNAsBRm6.png) *** ## 反思 這題給的範圍或數量不會太大,可以較放心的去寫。只不過在真正測試或操作前,都不會知道哪裡有問題,或許在處理問題之前,需要思慮到更多的結果,亦或是透過各種測資將一個個錯誤的地方解決,才能達到實質上的解決。 ### 更動後的心智圖 ![c292f](https://hackmd.io/_uploads/S1VkcBAma.png) *** ## 題目來源 [C292. APCS2017-03-04-3數字龍捲風(from Zero Judge)](https://zerojudge.tw/ShowProblem?problemid=c292) 2023-11-12 編寫此文 2023-11-13 勘誤、調整結構 2023-11-19 調整結構 2023-12-10 文法勘誤