九连环问题(递归)

题目描述

九连环是一种流传于山西省的传统民间的智力玩具,由九个圆环相连成串,以解开为胜。

九连环的九个环,一环扣一环地套在钗上。除了第 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久的问题

posted @ 2021-01-07 19:01  幽灵轩  阅读(1533)  评论(0编辑  收藏  举报