递推递归

1.汉诺塔问题
hanoi 1.0
Time limit1000 ms,Memory limit65535 kB
描述
有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆: 每次只能移动一个圆盘; 大盘不能叠在小盘上面。 提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。 问:如何移?最少要移动多少次?

Input
输入为一个整数后面跟三个单字符字符串。
整数为盘子的数目,后三个字符表示三个杆子的编号。

Output
输出每一步移动盘子的记录。一次移动一行。
每次移动的记录为例如3:a->b 的形式,即把编号为3的盘子从a杆移至b杆。
我们约定圆盘从小到大编号为1, 2, …n。即最上面那个最小的圆盘编号为1,最下面最大的圆盘编号为n。
Sample Input
3 a b c
Sample Output
1:a->c
2:a->b
1:c->b
3:a->c
1:b->a
2:b->c
1:a->c
思路
解法的基本思想是递归。假设有A、B、C三个塔,A塔有N块盘,目标是把这些盘全部移到C塔。那么先把A塔顶部的N-1块盘移动到B塔,再把A塔剩下的大盘移到C,最后把B塔的N-1块盘移到C。 每次移动多于一块盘时,则再次使用上述算法来移动。

AC代码

#include<iostream>
#include<string>
using namespace std;
void moveOne(int numDisk, string init, string desti) 
{
	cout<<numDisk<<":"<<init<<"->"<<desti<< endl;
}

void move(int numDisks, string init, string temp, string desti)
{
	if(numDisks == 1)
		moveOne(1, init, desti);
	else
	{
		move(numDisks-1, init, desti, temp);
		moveOne(numDisks, init, desti);		
		move(numDisks-1, temp, init, desti); 
	}
} 
 
int main()
{
	int numDisks;
	string init,temp,desti;
	cin>>numDisks>>init>>temp>>desti;
	move(numDisks,init,temp,desti);	 
	return 0;
}

hanoi 2.0
描述
Gardon是个怕麻烦的人(恩,就是爱偷懒的人),很显然将64个圆盘逐一搬动直到所有的盘子都到达第三个柱子上很困难,所以Gardon决定作个小弊,他又找来了一根一模一样的柱子,通过这个柱子来更快的把所有的盘子移到第三个柱子上。下面的问题就是:当Gardon在一次游戏中使用了N个盘子时,他需要多少次移动才能把他们都移到第三个柱子上?很显然,在没有第四个柱子时,问题的解是2^N-1,但现在有了这个柱子的帮助,又该是多少呢?

Input
包含多组数据,每个数据一行,是盘子的数目N(1<=N<=64)。

Output
对于每组数据,输出一个数,到达目标需要的最少的移动数。
Sample Input
1
3
12
Sample Output
1
5
81

(好难!下面是师哥的思路和AC代码

思路
d(n)表示对于3根柱子把n个盘从A柱移动到C柱所需要的最小步数。然后假设d(n) = 2 ∗ d(n − 1) + 1, d(1) = 1,可以得到通项公式:d(n) = 2^n − 1,f(n)表示求解n盘4塔问题的最少步数,则f(n) = min(2 ∗ f(i) + d(n − i)), 1 <= i <= nf(1) = 1上式的含义是,先把i个盘子在4塔模式下移动到B柱,然后把n-i个盘子在3塔模式下移动到D柱,最后把i个盘子在4塔模式下移动到D柱,枚举所有的i,取最小值。
AC代码

#include <ctime>
#include <cstdlib>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<cstdio>
#include<string>
#include<string.h>
#include<list>
#include<queue>
#include<sstream>
#include<vector>
#include <cassert> // assert
#include<set>
#include<map>
#include<deque>
#include<stack>
using namespace std;
#define debug(x) cout<<"###"<<x<<"###"<<endl;
const int INF=0x3f3f3f3f,mod=1e9,Maxn=1e2;
const double eps=1e-8;
typedef unsigned long long ull;
ull f[Maxn];
void init() {
	memset(f,0x3f,sizeof(f));
	f[1]=1;
	f[2]=3;
	for(int i=3; i<=64; i++) {
		for(int x=1; x<i; x++) {
			if(2*f[x]+(1ull*1<<(i-x))-1<f[i]) {
				f[i]=2*f[x]+(1ull*1<<(i-x))-1;
			}
		}
	}
}
int main() {
	init();
	int n;
	while(~scanf("%d",&n)) {
		cout<<f[n]<<endl;
	}
	return 0;
}

对于汉诺塔的详细补充可见一个大佬的博客 hanoi

2.放苹果(POJ-1664)
描述
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

Input
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
Output
对输入的每组数据M和N,用一行输出相应的K。
Sample Input
1
7 3
Sample Output
8

思路
如果只有一个盘子或者没有苹果,那么ans=1。
如果苹果数小于盘子数,则情况可等价于只有苹果数个盘子。
若苹果数大于盘子数,分两种情况

  1. 有空盘子:apple(m,n-1)
  2. 全满:apple(m-n,n)//即每个盘子上至少有一个苹果,再分配

AC代码

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
long long a[25];
long long apple(int m,int n)
{
	if(m==0||n==1)
		return 1;
	if(m<n)
		return apple(m,m);
	else
		return apple(m,n-1)+apple(m-n,n);
} 
int main()
{
	int t,m,n;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&m,&n);
		printf("%d\n",apple(m,n));
	}
	return 0;
}

3.杨辉三角(hdu-2032)
Time limit1000 ms,Memory limit32768 kB
描述
还记得中学时候学过的杨辉三角吗?具体的定义这里不再描述,你可以参考以下的图形:
    1
   1 1
   1 2 1
  1 3 3 1
 1 4 6 4 1
1 5 10 10 5 1
Input
输入数据包含多个测试实例,每个测试实例的输入只包含一个正整数n(1<=n<=30),表示将要输出的杨辉三角的层数。
Output
对应于每一个输入,请输出相应层数的杨辉三角,每一层的整数之间用一个空格隔开,每一个杨辉三角后面加一个空行。
Sample Input
2 3
Sample Output
1
1 1

1
1 1
1 2 1

AC代码

#include<stdio.h>
int a[35][35];
int main()
{
	int n;
	for(int i=0;i<30;i++)
	{
		a[i][0]=1;
		a[i][i]=1;
	}
	for(int i=1;i<30;i++)
	{
		for(int j=1;j<30;j++)
		{
			a[i][j]=a[i-1][j-1]+a[i-1][j];
		}
	}
	while(~scanf("%d",&n))
	{
	for(int i=0;i<n;i++)
	{
		if(i%2==0)
		{
			for(int j=0;j<=i/2;j++)
			{
				if(i==0)
				{
					printf("%d",a[i][j]);
				}
				else
				{
					printf("%d",a[i][j]);
					printf(" ");
				}
			}
			for(int j=i/2-1;j>=0;j--)
			{
				printf("%d",a[i][j]);
				if(j!=0) {printf(" ");
				}
			}
			printf("\n");
		}
		else
		{
			for(int j=0;j<=i/2;j++)
			{
				printf("%d",a[i][j]);
				printf(" ");
			}
			for(int j=i/2;j>=0;j--)
			{
				printf("%d",a[i][j]);
				if(j!=0) {printf(" ");
				}
			}
			printf("\n");
		}
	}
	printf("\n");
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值