B3940 [GESP樣題 四級] 填幻方
題目
在一個N×N?的正方形網格中,每個格子分別填上從 1 到 N×N?的正整數,使得正方形中任一行、任一列及對角線的幾個數之和都相等,則這種正方形圖案就稱為“幻方”(輸出樣例中展示了一個3×3?的幻方)。我國古代稱為“河圖”、“洛書”,又叫“縱橫圖”。幻方看似神奇,但當?N?為奇數時有很方便的填法:
- 一開始正方形中沒有填任何數字。首先,在第一行的正中央填上?1。
- 從上次填數字的位置向上移動一格,如果已經在第一行,則移到同一列的最后一行;再向右移動一格,如果已經在最右一列,則移動至同一行的第一列。如果移動后的位置沒有填數字,則把上次填寫的數字的下一個數字填到這個位置。
- 如果第 2 步填寫失敗,則從上次填數字的位置向下移動一格,如果已經在最下一行,則移到同一列的第一行。這個位置一定是空的(這可太神奇了!)。把上次填寫的數字的下一個數字填到這個位置。
- 重復 2、3 步驟,直到所有格子都被填滿,幻方就完成了!
快來編寫一個程序,按上述規則,制作一個N×N?的幻方吧。
輸入為一個正奇數?N,保證 3≤N≤21。
輸出?N?行,每行?N個空格分隔的正整數,內容為N×N?的幻方。
運行代碼
#include <iostream>
#include <vector>
using namespace std;
void FN(int N) { vector<vector<int>> FF(N, vector<int>(N, 0)); int num = 1; int r = 0, c = N / 2; while (num <= N * N) { // 將數字填入當前位置 FF[r][c] = num++; // 計算下一個位置 int R= (r - 1 + N) % N; int C = (c + 1) % N; // 檢查下一個位置是否已被占用 if (FF[R][C] != 0) { r = (r+ 1) % N; } else { r = R; c = C; } } // 打印幻方 for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { cout << FF[i][j] << (j < N - 1 ? " " : "\n"); } }
}
int main() { int N; cin >> N; if (N % 2 == 0 || N < 3 || N > 21) { return 1; } FN(N); return 0;
}
思路
- 初始化一個N x N的二維向量
vector<vector<int>> FF(N, vector<int>(N, 0));
,用來存儲幻方數據,初始值全為0。設置計數器num = 1
,用于填充數字。 - 定義兩個變量
r
和c
來追蹤當前填充的位置,初始位置設在中心(r = 0, c = N / 2)
。 - 使用while循環,直到所有數字填充完畢(
num <= N * N
)。 - 在當前位置
(r, c)
放入數字num
,然后遞增num
。 - 計算下一個位置的行
R
和列C
,使用取模運算保證位置在矩陣范圍內。 - 如果下一個位置已占用,則向下一行移動;否則,更新當前位置為計算出的下一個位置。
B3850 [GESP202306 四級] 幸運數
題目
小明發明了一種 "幸運數"。一個正整數,其偶數位不變(個位為第?1?位,十位為第?2?位,以此類推),奇數位做如下變換:將數字乘以?7,如果不大于?9?則作為變換結果,否則把結果的各位數相加,如果結果不大于?9?則作為變換結果,否則(結果仍大于?9)繼續把各位數相加,直到結果不大于?9,作為變換結果。變換結束后,把變換結果的各位數相加,如果得到的和是?8?的倍數,則稱一開始的正整數為幸運數。
例如,16347:第?1位為?7,乘以?7?結果為 49,大于 9,各位數相加為13,仍大于9,繼續各位數相加,最后結果為4;第3?位為3,變換結果為3;第?55?位為?1,變換結果為?7。最后變化結果為?76344,對于結果76344?其各位數之和為24,是?8的倍數。因此 16347?是幸運數。
輸入第一行為正整數?N,表示有?N個待判斷的正整數。約定 1≤N≤20。從第?2?行開始的?N?行,每行一個正整數,為待判斷的正整數。約定這些正整數小于?10^12。
輸出?N行,對應?N?個正整數是否為幸運數,如是則輸出 'T',否則輸出 'F'。
提示:不需要等到所有輸入結束在依次輸出,可以輸入一個數就判斷一個數并輸出,再輸入下一個數。
運行代碼
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int FN(long long num) { int sum = 0; while (num > 0) { sum += num % 10; num /= 10; } return sum;
}
// 函數:對奇數位進行變換
string FF(const string& numStr) { string result; for (size_t i = 0; i < numStr.size(); ++i) { if (i % 2 == 0) { // 偶數位直接添加 result += numStr[i]; } else { // 奇數位進行變換 int digit = numStr[i] - '0'; int t = digit * 7; while (t> 9) { t= FN(t); } result +=to_string(t); } } return result;
}
// 函數:判斷是否為幸運數
bool Number(const string& numStr) { string t = FF(numStr); return FN(stoll(t)) % 8 == 0;
}
int main() { int N; cin >> N; cin.ignore(); // 忽略可能存在的換行符 while (N--) { string numStr; getline(cin, numStr); // 讀取一行字符串作為數字 if (Number(numStr)) { cout << "T" << endl; } else { cout << "F" << endl; } } return 0;
}
思路
- 計算一個數的各位數之和。
FN
:對輸入的數字字符串的奇數位進行變換,并返回變換后的字符串。Number
:判斷一個數字字符串是否為幸運數。
在main
函數中,我們讀取要判斷的正整數個數N
,然后對每個正整數進行判斷并輸出結果。注意我們使用getline
來讀取每行的輸入,以正確處理可能包含前導零的情況。此外,我們使用stoll
將變換后的字符串轉換回long long
類型,以計算其各位數之和。