九連環問題(遞迴)
題目描述
九連環是一種流傳於山西省的傳統民間的智力玩具,由九個圓環相連成串,以解開為勝。
九連環的九個環,一環扣一環地套在釵上。除了第 1 號環可以隨時裝上或卸下以外,其它環裝上或卸下的條件是:在它的前面僅有緊靠它那一個環在釵上。即:當第 1 ~ i−2 號環都不在釵上,第 i−1 號環在釵上,這時可以裝上或卸下第 i 號環。
輸入格式
環數 操作(U表示裝上, D表示卸下)
輸出格式
裝上或卸下九連環的操作步驟
每行顯示一步操作,具體格式為:
環號: U或D (U表示裝上,D表示卸下)
樣例輸入1
3 U
樣例輸出1
1: U
2: U
1: D
3: U
1: U
樣例輸入2
4 D
樣例輸出2
2: D
1: D
4: D
1: U
2: U
1: D
3: D
1: U
2: D
1: D
題意理解
這道題目我理解也是看了挺久
最總要的一句話就是:當第 1 ~ i−2 號環都不在釵上,第 i−1 號環在釵上,這時可以裝上或卸下第 i 號環。
正解思路
我第一想法就是一個間接遞迴
我設定兩個函式
f(i,1)函式代表,當前局面為[0,i]為空,裝上單環i
f(i,0)函式代表,當前局面為[0,i-1]為空,i存在,卸下單環i,
digui(i,1),表示[0,i]為空,[0,i]全裝上
digui(i,0),表示[0,i]全都存在,[0,i]全卸下來
思路我很詳細的註釋在程式碼裡面了
#include<bits/stdc++.h> using namespace std; void f(int n,int k) { if(n==0)return ; if(n==1) { printf("%d: %c\n",n,k==1?'U':'D'); return ; } f(n-1,1);//裝上單環n-1 printf("%d: %c\n",n,k==1?'U':'D');//裝上或卸下單環n f(n-1,0);//卸下單環n-1 } void digui(int n,int k) { if(n==0)return ; if(n==1) { f(n,k); return ; } if(k) { f(n-1,1);//先裝上單環n-1 printf("%d: %c\n",n,k==1?'U':'D');//裝上單環n digui(n-2,1);//裝上全環n-2 } else { digui(n-2,0);//卸下全環n-2 printf("%d: %c\n",n,k==1?'U':'D');//卸下單環n f(n-1,0);//卸下單環n-1 } } int main() { int n;char c; scanf("%d %c",&n,&c); digui(n,c=='U'?1:0);//裝上或卸下,全部的環1-n }
做題時思路
給大家分享我自己打這題踩的坑,大家共勉
看題目第一反應
很顯然的遞迴,模擬一遍之後我的第一想法,是間接遞迴
因為總結不出直接遞迴的寫法,也沒試過
我程式碼第一遍打完之後
整題10分拿了5分
因為PTA是不允許下載測試樣例的
因為以前自己也出過題目,所以我知道資料應該是對半的
一半取的,一般卸的,抱著試一試的心態
我就在程式碼裡面加了一句,如果是'U'操作,那麼直接結束程式
果然還是拿了5分,這時候我就知道是我程式'U'操作有問題,'D'操作是沒問題的
然後我改了接近一個小時的bug,實在找不出來我U操作程式碼的思路哪裡有問題
於是我就一個大佬一起幫忙打這題,他打完之後交上去ac了,
他找我程式碼的思路,覺得沒有任何問題
我倆程式對拍,結果發現輸出一模一樣
我倆找debug快一個半小時
然後我們就開始質疑,發現我程式真的沒問題,就開始質疑編譯器了
我們一直把重點放在遞迴函式上面,發現main函式,我char c定義成int c
int main() {
int n,c;
scanf("%d %c",&n,&c);
int k=c=='U'?1:0;
if(k)digui(n,1);
else digui(n,0);
}
我把int改成char之後,就ac了……
我就去查一下PTA的編譯器是6.5.0的
我的編譯器是8.1.0
有時候犯這種弱智錯誤的情況,可能你的編譯器太聰明瞭
以至於你改不出來
所以出現bug的情況,就可以用到pta網站自帶的自測
就可以一定意義上面避免編譯器版本不同而帶來訂正N久的問題