递推求解

递推求解

步骤

  • 得到简单情况的解,譬如 n=1, n=2 等;
  • 假设规模为 n-1 的情况已经解决;
  • 当规模扩大到 n 时,如何枚举出所有的情况,并且要确保对于每一种子情况都能用已经得到的数据解决;

例题:

  1. 大家都知道斐波那契数列,现在要求输入一个整数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. 一只青蛙一次可以跳上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. 一只青蛙一次可以跳上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;
    }
};
  1. (牛客网)我们可以用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;
    }
}
  1. (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;
}
  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;
}
  1. (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;
}
  1. (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;
    }
}
  1. (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;
    }
        
}
  1. (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]);
    }
}
posted @ 2019-03-19 20:36  静_渊  阅读(246)  评论(0编辑  收藏  举报