「Day 1—递归问题」

递归问题

定义

简洁来说就是一个函数不断调用自身的一个过程。

习题

汉诺塔问题

思路

对于这个经典的问题,我们考虑了使用递归的做法,由于盘子是在三个底座上来回辗转的,所以我们要确定起始座,辅助座,和目标座。我们专注于最下面的最大的那个盘子,先将盘子都放到辅助座上,等到只剩最大的,将其放到目标座上,再继续由辅助座向目标座转移。

代码
void hanoi(int n,char a,char b,char c){
	if(n > 0){
		hanoi(n - 1,a,c,b);
		cout<<a<<"->"<<n<<"->"<<b;
		hanoi(n - 1,b,a,c);
	}
	return;
}

P5657 [CSP-S2019] 格雷码

思路

首先我们在读题的过程中就可以观察到,对于 \(n\) 位的格雷码,必须由 \(n-1\) 推出来,我们不免想到通过递归来实现,但在仔细观察之后会发现:

\(3\) 位格雷码为例,分别是 000,001,011,010,110,111,101,100;那么他们是怎么得出来的呢,观察下图:

我们发现格雷码是有规律的,分为前一半和后一半,前为 \(0\),后为 \(1\),比较像一个二叉树,因为后面一半是逆序,所以左右对称。在左半边,所以如果根为 \(0\),那么左子树为 \(0\),右子树为 \(1\);如果根为 \(1\),那么左子树为 \(1\),右子树为 \(0\)。右半边则相反.

代码
#include<iostream>
#include<cmath>
using namespace std;

unsigned long long n,k;
bool flag = 0;

int main(){
	cin >> n >> k;
	unsigned long long mid = pow(2,n-1);
	while(mid){
		if(!flag){
			if(k < mid){
				cout << "0";
				flag = 0;
			}
			else if(k >= mid){
				cout << "1";
				flag = 1;
				k = k - mid;
			}
		}
		else if(flag){
			if(k < mid){
				cout << "1";
				flag = 0;
			}
			else if(k >= mid){
				cout << "0";
				flag = 1;
				k = k - mid;
			}
		}
		mid /= 2;
	}
	return 0;
}

UVA679 Dropping Balls

思路

对于此题,我们依旧按朴素的思路,将 \(I\) 之前全模拟一遍,但是,我们发现,会 \(TLE\)。故我们进行一些优化,根为n,则左子树为 \(2*n\),右子树为 \(2*n+1\),接下来我们需要看第 \(I\) 个小球会走哪里,通过观察发现,当 \(I\) 为偶数时,先走左边,反之。

代码
#include<iostream>
using namespace std;

int T;

int main(){
	
	cin >> T;
	
	while(T--){
		int deep,id,ans = 1;
		cin >> deep >> id;
		for(int i = 1;i < deep;i++){
			if(id % 2 == 1){
				ans = ans * 2;
				id = id / 2 + 1;
			}
			else{
				ans = ans * 2 + 1;
				id = id / 2;
			}
		}
		cout << ans <<"\n";
	}
	
	
	return 0;
}
posted @ 2024-08-04 22:21  To_Carpe_Diem  阅读(11)  评论(1编辑  收藏  举报