1. 程式人生 > 實用技巧 >九連環問題(遞迴)

九連環問題(遞迴)

題目描述

九連環是一種流傳於山西省的傳統民間的智力玩具,由九個圓環相連成串,以解開為勝。

九連環的九個環,一環扣一環地套在釵上。除了第 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久的問題