递推与递归(一)

递推与递归思想:将一个很大的任务分解成规模小一些的子任务,子任务分成更小的子任务,直到遇到初始条件,最后整理归纳解决大任务

题目一:数楼梯

对于第n阶台阶,可以由第n-1级台阶上1阶或由第n-2级台阶上2阶得到,由此得到递推式
f [ n ] = f [ n − 1 ] + f [ n − 2 ] f[n] = f[n-1]+f[n-2] f[n]=f[n1]+f[n2]
初始化 f [ 1 ] = 1 , f [ 2 ] = 2 f[1] = 1,f[2] = 2 f[1]=1,f[2]=2
代码如下:

#include <bits/stdc++.h>
using namespace std;
vector<int> add(vector<int> A,vector<int> B)
{
    vector<int> C;
    int t = 0;
    for(int i = 0;i < A.size() || i < B.size();i++)
    {
        if(i < A.size())
            t += A[i];
        if(i < B.size())
            t += B[i];
        C.push_back(t%10);
        t /= 10;
    }
    while(t)
    {
        C.push_back(t%10);
        t /= 10;
    }
    return C;
}
int main()
{
    int n;
    cin >> n;
    vector<int> a,b;
    a.push_back(1);
    b.push_back(2);
    if(n == 0)
    {
        cout << "0";
        return 0;
    }
    else if(n == 1)
    {
        cout << "1";
        return 0;
    }
    else if(n == 2)
    {
        cout << "2" << endl;
    }
    else if(n > 3)
    {
        vector<int> ans;
        for(int i = 3;i <= n;i++)
        {
            ans = add(a,b);//高精度加法
            a = b;
            b = ans;
        }
        for(int i = ans.size()-1;i >= 0;i--)
        {
            cout << ans[i];
        }
    }
    return 0;
}

题目二:过河卒

已知马的坐标cx,cy,则通过dx[9] = {0,2,1,-1,-2,-2,-1,1,2} ,dy[9] = {0,1,2,2,1,-1,-2,-2,-1}得到马可以到达的点,而这些点是卒不可以到的点,并且卒只可以向右走或向下走,于是得到递推式 f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i ] [ j − 1 ] f[i][j] = f[i-1][j]+f[i][j-1] f[i][j]=f[i1][j]+f[i][j1]
代码如下:

#include <bits/stdc++.h>

using namespace std;
const int N = 40;
long long a[N][N];
bool flag[N][N];
int dx[9] = {0,-2,-1,1,2,2,1,-1,-2};
int dy[9] = {0,1,2,2,1,-1,-2,-2,-1};
int main()
{
    int cx,cy;
    int bx,by;
    cin >> bx >> by >> cx >> cy;
    bx += 2;
    by += 2;
    cx += 2;
    cy += 2;//防止出现负数使得数组越界
    a[2][1] = 1;
    for(int i = 0;i <= 8;i++)
        flag[cx+dx[i]][cy+dy[i]] = true;
    for(int i = 2;i <= bx;i++)
    {
        for(int j = 2;j <= by;j++)
        {
            if(flag[i][j])
                continue;
            a[i][j] = a[i-1][j]+a[i][j-1];
        }
    }
    cout << a[bx][by];
    return 0;
}

题目三:

也就是一个由队列进入到栈中,同时栈中数字出栈的过程
对于数组 f [ N ] [ N ] f[N][N] f[N][N],i已经出栈的数字个数,j表示进栈的数字个数, f [ i ] [ j ] f[i][j] f[i][j]表示方案数
初始化:在出栈数为0时,对于已入栈的数字只有一种输出方案
递推式:
(1)如果当前栈内已空 ( i = = j , 出栈数 = = 入栈数 ) (i == j,出栈数 == 入栈数) i==j,出栈数==入栈数)则下一步只能入栈,当前的方案数与出栈数为i-1时相同 f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j] = f[i-1][j] f[i][j]=f[i1][j]
(2)如果当前栈非空 ( i < j , 出栈数 < 入栈数) (i < j,出栈数 < 入栈数) i<j,出栈数<入栈数)则此时既可以入栈也可以出栈, f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i ] [ j − 1 ] f[i][j] = f[i-1][j]+f[i][j-1] f[i][j]=f[i1][j]+f[i][j1]
(或者用卡特兰数,暂时还不会)
代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 30;
long long f[N][N]; //i个出栈,j个进栈
int main()
{
    int n;
    cin >> n;
    for(int i = 0;i <= n;i++)
    {
        f[0][i] = 1;
    }
    for(int i = 1;i <= n;i++)
    {
        for(int j = i;j <= n;j++)
        {
            if(i == j)
                f[i][j] = f[i-1][j];
            else
                f[i][j] = f[i-1][j] + f[i][j-1];
        }
    }
    cout << f[n][n];
    return 0;
}

题目四:数的计算

求合法数列,已6为例
6
6,1
6,2
6,3
6,2,1
6,3,1
可以发现对于数n,其可行的方案数为所有 < = n / 2 <=n/2 <=n/2的方案数之和
代码如下:

#include <bits/stdc++.h>

using namespace std;
const int N = 1010;
long long f[N];
int main()
{
    int n;
    cin >> n;
    for(int i = 1;i <= n;i++)
    {
        f[i]++;//至少有一个就是自己本身
        for(int j = 1;j <= i/2;j++)
        {
            f[i] += f[j];
        }
    }
    cout << f[n];
    return 0;
}

题目五:Function

即按照题目要求实现递归函数 w ( a , b , c ) w(a,b,c) w(a,b,c)
代码如下:

#include <bits/stdc++.h>
using namespace std;
long long ans = 0;
const int N = 30;
long long all[N][N][N];
long long w(int a,int b,int c)
{
    if(a <= 0 || b <= 0 || c <= 0)
        return 1;
    if(a > 20 || b > 20 || c > 20)
        return w(20,20,20);
    if(a < b && b < c)
    {
        if(all[a][b][c-1] == 0)
        {
            all[a][b][c-1] = w(a,b,c-1);
        }
        if(all[a][b-1][c-1] == 0)
        {
            all[a][b-1][c-1] = w(a,b-1,c-1);
        }
        if(all[a][b-1][c] == 0)
        {
            all[a][b-1][c] = w(a,b-1,c);
        }
        all[a][b][c] = all[a][b][c-1] + all[a][b-1][c-1] - all[a][b-1][c];
    }
    else
    {
        if(all[a-1][b][c] == 0)
		{
			all[a-1][b][c] = w(a-1, b, c);
		}
		if(all[a-1][b-1][c] == 0)
		{
			all[a-1][b-1][c] = w(a-1, b-1 ,c);
		}
		if(all[a-1][b][c-1] == 0)
		{
			all[a-1][b][c-1] = w(a-1, b, c-1);
		}
		if(all[a-1][b-1][c-1] == 0)
		{
			all[a-1][b-1][c-1] = w(a-1, b-1, c-1);
		}
		all[a][b][c] = all[a-1][b][c] + all[a-1][b][c-1] + all[a-1][b-1][c] - all[a-1][b-1][c-1];
    }
    return all[a][b][c];
}
int main()
{
    int a,b,c;
    while(true)
    {
        cin >> a >> b >> c;
        if(a == b && b == c && a == -1)
            break;
        cout << "w(" << a << ", " << b << ", " << c << ") = " << w(a,b,c) << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值