字黑洞 題解|循環(huán)結(jié)構(gòu)詳細(xì)講解)
這道題是 GESP 2023年9月 的真題難度定位在 二級(jí)。別看它代碼不長(zhǎng)里面對(duì)循環(huán)結(jié)構(gòu)的考查很到位我第一次做的時(shí)候也踩了坑。下面把完整思路梳理一遍。題目來源ACGO A46099 2023年9月 二級(jí)賽事場(chǎng)次2023年9月 二級(jí)一、題目信息題目名稱數(shù)字黑洞賽事場(chǎng)次2023年9月 二級(jí)難度定位二級(jí)涉及知識(shí)點(diǎn)循環(huán)結(jié)構(gòu)題目鏈接https://www.acgo.cn/problemset/info/46099坑點(diǎn)這題失分基本都在這循環(huán)三要素初值、條件、步進(jìn)循環(huán)不變式。題意簡(jiǎn)述給定一個(gè)三位數(shù)要求各位不能相同。例如 352 是符合要求的 112 是不符合要求的。將這個(gè)三位數(shù)的三個(gè)數(shù)字重新排列得到的最大的數(shù)減去得到的最小的數(shù)形成一個(gè)新的三位數(shù)。對(duì)這個(gè)新的三位數(shù)可以重復(fù)上述過程。神奇的是最終一定會(huì)得到 495 試試看重新排列 352 得到的最大數(shù)為 532 最小數(shù)為 235 它們的差是 297 變換 297 得到 972-279693 變換 693 963-369594 變換 594 954-459495 。因此 經(jīng)過 4 次變換得到了 ?,F(xiàn)在輸入的三位數(shù)你能通過編程得出這個(gè)三位數(shù)經(jīng)過多少次變換能夠得到 495 嗎前置知識(shí)這道題用到的前置知識(shí)不多我們先把它補(bǔ)齊即使你剛學(xué)到這里也能看懂。for 循環(huán)的標(biāo)準(zhǔn)寫法for(int i1;in;i)表示 i 從 1 遞增到 n每次循環(huán)體執(zhí)行完 i 自動(dòng)加 1。競(jìng)賽中我們習(xí)慣從 1 開始計(jì)數(shù)這樣可以避免下標(biāo)越界的麻煩。while 循環(huán)適合循環(huán)次數(shù)不確定的場(chǎng)景只要條件成立就一直執(zhí)行寫的時(shí)候一定要確保循環(huán)變量會(huì)被修改否則會(huì)死循環(huán)。二、思路分析先看清楚題目要我們做什么把題目讀兩遍我們提取出關(guān)鍵信息輸入是什么、要輸出什么、有哪些約束條件。這道題考查的是循環(huán)結(jié)構(gòu)屬于這類題里比較基礎(chǔ)的一道把題目要求一步步翻譯成代碼邏輯就能解決。解題步驟拆解按題目要求讀入全部輸入數(shù)據(jù)。按題意逐項(xiàng)處理這一步是核心要保證每一步都對(duì)應(yīng)題目里的一句話。按題目規(guī)定的格式輸出結(jié)果。需要說明的是上面這個(gè)思路是把題目要求直譯成代碼得到的沒有用到什么高級(jí)技巧。對(duì)于這類基礎(chǔ)題讀準(zhǔn)題意加寫對(duì)邊界比追求巧妙解法更重要因?yàn)榭荚嚴(yán)镞@種題是必須拿滿分的。三、完整代碼 逐行注釋#include iostream using namespace std; int main() { // 讀取輸入的三位數(shù) int n 0; // 初始化 cin n; // 讀入 // 循環(huán)進(jìn)行變換直到得到495 for (int t 0; ; t) { // 遍歷 // 如果當(dāng)前的三位數(shù)已經(jīng)是495則輸出變換次數(shù)并結(jié)束循環(huán) if (n 495) { // 判斷 cout t endl; // 輸出 break; } // 分別提取當(dāng)前三位數(shù)的各位數(shù)字 int m0 n % 10, m1 n / 10 % 10, m2 n / 100; int tmax 0, tmin 0; // 按照規(guī)定重新排列數(shù)字得到最大值和最小值 if (m0 m1 m1 m2) { // 判斷 tmax m0 * 100 m1 * 10 m2; tmin m2 * 100 m1 * 10 m0; } else if (m0 m2 m2 m1) { tmax m0 * 100 m2 * 10 m1; tmin m1 * 100 m2 * 10 m0; } else if (m1 m0 m0 m2) { tmax m1 * 100 m0 * 10 m2; tmin m2 * 100 m0 * 10 m1; } else if (m1 m2 m2 m0) { tmax m1 * 100 m2 * 10 m0; tmin m0 * 100 m2 * 10 m1; } else if (m2 m0 m0 m1) { tmax m2 * 100 m0 * 10 m1; tmin m1 * 100 m0 * 10 m2; } else { // m2 m1 m1 m0 tmax m2 * 100 m1 * 10 m0; tmin m0 * 100 m1 * 10 m2; } // 計(jì)算新的三位數(shù)并更新 n n tmax - tmin; } return 0; }四、代碼分段拆解為了看得更清楚我們把代碼按功能分成幾段解釋。第一步引入頭文件#include iostream using namespace std;#include iostream提供輸入輸出功能using namespace std;讓我們能直接寫cin、cout而不用加前綴。這兩行是幾乎所有 C 程序的開頭照寫即可。第二步讀入數(shù)據(jù)cin n;注意變量的類型要能裝下題目的數(shù)據(jù)。數(shù)據(jù)可能超過 21 億時(shí)要改用long long。第三步核心處理邏輯for (int t 0; ; t) {這一段是整道題的關(guān)鍵也是循環(huán)結(jié)構(gòu)的體現(xiàn)??囱h(huán)的三個(gè)要素從哪里開始、什么時(shí)候結(jié)束、每次怎么變化。這三個(gè)要素任何一個(gè)寫錯(cuò)結(jié)果都會(huì)不對(duì)。第四步按要求輸出cout t endl;輸出格式必須和題目要求的完全一致。很多同學(xué)算法完全正確卻因?yàn)樯倭艘粋€(gè)換行或者空格多寡不對(duì)而 WA這種分丟得最可惜。五、實(shí)例模擬下面用樣例數(shù)據(jù)走一遍流程你能看到每一步變量是怎么變化的。以題目的第一組樣例為例樣例輸入352樣例輸出4把這份輸入代進(jìn)代碼程序會(huì)先把數(shù)據(jù)依次讀入然后進(jìn)入循環(huán)逐個(gè)判斷把滿足條件的值累積起來最后按格式輸出。建議你對(duì)照著代碼在紙上走一遍前兩次循環(huán)確認(rèn)自己對(duì)每一步的理解都和程序一致。六、踩坑總結(jié)下面是做這道題時(shí)最容易出錯(cuò)的地方對(duì)照自己的代碼檢查一下變量類型選錯(cuò)雖然本題范圍不大但養(yǎng)成習(xí)慣——凡是不確定范圍時(shí)累加變量一律用long long成本為零但能保命。輸出格式不符題目要求輸出幾行就輸出幾行行末換行、數(shù)字之間的空格都要嚴(yán)格對(duì)齊算法對(duì)了但格式錯(cuò)了同樣判 WA這種分丟得最冤。特殊情況沒特判把最小數(shù)據(jù)、最大數(shù)據(jù)、答案恰好等于 0 的情況各測(cè)一遍。特別是邊界輸入出題人最喜歡在這里設(shè)陷阱。七、知識(shí)點(diǎn)拓展最后總結(jié)一下這道題帶給我們的通用經(jīng)驗(yàn)本題考查循環(huán)結(jié)構(gòu)的基本寫法這類題在考試中屬于必得分項(xiàng)要練到能默寫。寫完代碼后建議自己造幾組邊界數(shù)據(jù)測(cè)試特別是最小值和最大值。同一知識(shí)點(diǎn)在不同場(chǎng)次反復(fù)出現(xiàn)把這道題的寫法吃透后面遇到同類題可以直接套用。八、適用人群適合正在備考 二級(jí)、想確認(rèn)自己循環(huán)結(jié)構(gòu)基礎(chǔ)是否扎實(shí)的同學(xué)。這道題就講到這里。我會(huì)持續(xù)更新各場(chǎng)次真題的詳細(xì)拆解需要系統(tǒng)復(fù)習(xí)的同學(xué)可以關(guān)注這個(gè)系列。有問題歡迎評(píng)論區(qū)討論。