递推求解
递推求解
步骤
- 得到简单情况的解,譬如 n=1, n=2 等;
- 假设规模为 n-1 的情况已经解决;
- 当规模扩大到 n 时,如何枚举出所有的情况,并且要确保对于每一种子情况都能用已经得到的数据解决;
例题:
- 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0):
class Solution {
public:
int Fibonacci(int n) {
if(n==0)
return 0;
if(n==1)
return 1;
if(n==2)
return 1;
return Fibonacci(n-1)+Fibonacci(n-2);
}
};
- 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)
class Solution {
public:
int jumpFloor(int n) {
if(n==0)
return 1;
if(n==1)
return 1;
if(n==2)
return 2;
return jumpFloor(n-1)+jumpFloor(n-2);
}
};
- 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法:
class Solution {
public:
int jumpFloorII(int number) {
if (number==0)
return 1;
int sum = 0;
while(number>0){
number -= 1;
sum += jumpFloorII(number);
}
return sum;
}
};
- (牛客网)我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
class Solution {
public:
int rectCover(int number) {
if (number==0)
return 0;
if (number==1)
return 1;
if (number==2)
return 2;
return rectCover(number-1)+rectCover(number-2);
}
};
注: 上述解法在(HDU2046)显示超时,使用下面可通过。
#include<iostream>
int main()
{
using namespace std;
__int64 a[51]={0,1,2},n;
for(int i=3;i<=50;i++)
a[i]=a[i-1]+a[i-2];
while(cin>>n)
{
cout<<a[n]<<endl;
}
}
- (HDU 2050)我们看到过很多直线分割平面的题目,今天的这个题目稍微有些变化,我们要求的是n条折线分割平面的最大数目。比如,一条折线可以将平面分成两部分,两条折线最多可以将平面分成7部分,具体如下所示。
#include <iostream>
using namespace std;
int total(int n);
int main(){
int n,k;
cin >> n;
while(n--){
cin >> k;
cout << total(k) << endl;
}
return 0;
}
int total(int n){
if (n==1)
return 2;
return total(n-1) + 4*(n-1) + 1;
}
- (HDU2044) 有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。
#include <iostream>
using namespace std;
int number1(int n){
if(n==0)
return 1;
if(n== 1)
return 1;
if (n==2)
return 2;
return number1(n-1) + number1(n-2);
}
int main(){
int n,t1,t2;
cin >> n;
while(n--){
cin >> t1 >> t2;
cout << number1(t2-t1) << endl;
}
}
注释: 问题依旧是TLE,可先把数组存下来,然后直接读取;
#include <stdio.h>
int main()
{
int i, j, n;
__int64 d[51] = {1, 1, 2,};
for (i = 3; i < 51; i++)
d[i] = d[i-1] + d[i-2];
scanf("%d", &n);
while (n-- && scanf("%d%d", &i, &j) != EOF)
printf("%I64d\n", i > j ? 0 : d[j-i]);
return 0;
}
- (HDU 2045) 有排成一行的n个方格,用红(Red)、粉(Pink)、绿(Green)三色涂每个格子,每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色.求全部的满足要求的涂法.
#include <iostream>
using namespace std;
int main(){
int n,i;
long long pre[55]={-1,3,6,6};
for(i=4;i<55;i++)
pre[i] = pre[i-1] + 2*pre[i-2];
while(cin >>n)
cout << pre[n] << endl;
}
- (HDU 2049)假设一共有N对新婚夫妇,其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能.
思路:先找出m个选错新娘的新郎,m个新郎错排。
#include <iostream>
using namespace std;
int main(){
int i,c,n,m;
cin >> c;
long long n_l[21] = {1,1,2};
long long m_l[21] = {0,0,1,2};
for (i=3;i<21;i++){
n_l[i] = n_l[i-1]*i;
}
for (i=4;i<21;i++){
m_l[i] = (i-1)*m_l[i-1] + (i-1)*m_l[i-2];
}
while(c--){
cin >> n >> m;
cout << n_l[n]/n_l[m]/n_l[n-m] *m_l[m] << endl;
}
}
- (HDU 2047) 准备在上面刻下一个长度为n的只由"E" "O" "F"三种字符组成的字符串(可以只有其中一种或两种字符,但绝对不能有其他字符),阿牛同时禁止在串中出现O相邻的情况,
#include <iostream>
using namespace std;
int main(){
int n,i;
long long list[41]={0,3,8};
for (i=3;i<41;i++)
list[i] = 2*list[i-1] + 2*list[i-2];
while(cin >>n){
cout << list[n] << endl;
}
}
- (HDU 2048)首先,所有参加晚会的人员都将一张写有自己名字的字条放入抽奖箱中;然后,待所有字条加入完毕,每人从箱中取一个字条;最后,如果取得的字条上写的就是自己的名字,那么“恭喜你,中奖了!”,求没有人获奖的概率。
思路: 错排公式。\(f(n)=(n-1)(f(n-1)+f(n-2)\)
如果最后一个人和\((n-1)\)中的一个交换后,正好满足错排,则为\((n-1)*f(n-1)\);
如果最后一个人和\((n-1)\)个人中的一个交换后,不满足情况,说明这两个人正好拿着对方的名字,所以\((n-1)*f(n-2)\);
#include <iostream>
using namespace std;
int main(){
int c,n,i;
long long list[21]={0,0,1,2};
long long list_d[21]={1,1,2,6};
for(i=4;i<21;i++){
list_d[i] = list_d[i-1]*i;
list[i] = (i-1)*(list[i-1]+list[i-2]);
}
cin >> c;
while(c--){
cin >> i;
printf("%.2f%%\n",100*(float)list[i]/list_d[i]);
}
}