竞赛兼考研复习day17(本阶段共80天)(递归与分治的四道思考题整理总结)

学习目标:

第十二届蓝桥杯C++第四次培训记录:递归与分治的四道思考题整理总结


学习内容:

问题1:双色汉诺塔整体移动分析过程

1、最简单情况(n==2)

a->b
a->c
b->c

2、递推公式:(将原问题缩减成规模为n-2的子问题)

第一步: n-2层 a->c
第二步: a->b
第三步: n-2层 c->b
第四步: a->c
第五步: n-2层 b->a
第六步: b->c
第七步: n-2层 a->c

  1. 双色汉诺塔整体移动要求n为偶数,所以递推公式中通过缩减成规模为n-2来控制每次递归的子问题中n也为偶数。

过程如图示
在这里插入图片描述

代码如下

#include <iostream>
using namespace std;
//双色汉诺塔整体移动
void hanoiTower2(int n,char A,char B,char C)
{
    if(n==2)
    {
        //a->b
        cout<<A<<"---->"<<B<<endl;
        //a->c
        cout<<A<<"---->"<<C<<endl;
        //b->c
        cout<<B<<"---->"<<C<<endl;
    }
    else
    {
        //第一步:  n-2 层  a->c
        hanoiTower2(n-2,A,B,C);
        //第二步: a->b
        cout<<A<<"---->"<<B<<endl;
        //第三步:  n-2层   c->b
        hanoiTower2(n-2,C,A,B);
        //第四步: a->c
        cout<<A<<"---->"<<C<<endl;
        //第五步: n-2层   b->a
        hanoiTower2(n-2,B,C,A);
        //第六步: b->c
        cout<<B<<"---->"<<C<<endl;
        //第七步: n-2层   a->c
        hanoiTower2(n-2,A,B,C);
    }
}
int main()
{
    int n;
    cin>>n;
    hanoiTower2(n,'A','B','C');
    return 0;
}

经过观察,发现双色汉诺塔整体移动与基本的单色汉诺塔移动完全一致,以n=4的情况为例:
在这里插入图片描述
在这里插入图片描述
使用数学归纳法,可以证明双色汉诺塔整体移动与基本的单色汉诺塔移动完全一致。

问题2:双色汉诺塔分色移动分析过程

1、最简单情况(n==2)

指定上层分到B柱,下层分到C柱
a->b
a->c

2、递推公式:(将原问题缩减成规模为n-2的子问题)

第一步:把n-2层 整体从A移动到C
第二步:a->b
第三步:把n-2层 整体从C移动到B
第四步:a->c
第五步:把n-2层 整体从B移动到A
第六步:对(n-2)层分色

  • 前五歩做的都是移动操作,直接调用双色汉诺塔整体移动的函数即可。
  • 关键点是第五歩,要将n-2层从c移回a,因为要保持子问题与原问题在形式上一致性(从a分色到b、c),方便递归调用。
  • 第六歩是调用分色函数自身实现递归。

过程如图示
在这里插入图片描述
代码如下:

#include <iostream>
using namespace std;
//双色汉诺塔整体移动
void hanoiTower2(int n,char A,char B,char C)
{
    if(n==2)
    {
        cout<<A<<"---->"<<B<<endl;
        cout<<A<<"---->"<<C<<endl;
        cout<<B<<"---->"<<C<<endl;
    }
    else
    {
        hanoiTower2(n-2,A,B,C);
        cout<<A<<"---->"<<B<<endl;
        hanoiTower2(n-2,C,A,B);
        cout<<A<<"---->"<<C<<endl;
        hanoiTower2(n-2,B,C,A);
        cout<<B<<"---->"<<C<<endl;
        hanoiTower2(n-2,A,B,C);
    }
}

//分色
void hanoiTower2Separate(int n,char A,char B,char C)
{
    if(n==2)
    {
        cout<<A<<"---->"<<B<<endl;
        cout<<A<<"---->"<<C<<endl;

    }
    else
    {
        hanoiTower2(n-2,A,B,C);
        cout<<A<<"---->"<<B<<endl;
        hanoiTower2(n-2,C,A,B);
        cout<<A<<"---->"<<C<<endl;
        hanoiTower2(n-2,B,C,A);
        hanoiTower2Separate(n-2,A,B,C);

    }
}

int main()
{
    int n;
    cin>>n;
    hanoiTower2Separate(n,'A','B','C');
    return 0;
}

问题3:用分治算法在一个元素集合中寻找最大元素和最小元素的问题。

递归是一种技术,分治是一种思想。
使用分而治之的方法,一共三步,分、治、合。
:每一次都把区间以(i+j)/2为分界,把集合分成两个子区间。
:最小的子问题为,经过划分,该区间只剩下一个元素,那么这个元素同时是该区间的最大值与最小值;该区间剩下两个元素,那么较大的为该区间的最大值,较小的为该区间的最小值。(经验证,最小子问题可以缩减为只有一个元素,两个个元素的情况可以删去)
:用max1和min1来保存前半区的最大最小值,用max2和min2来保存后半区的最大最小值,比较两个子区间内的最大值与最小值,选出两个区间内较大的局部最大值与较小的局部最小值,最终可以得到全局的最大值和最小值。注意到此函数使用了引用的方法,将函数内的局部变量传递了出来。

#include <iostream>
using namespace std;
#include<cmath>
int l[10]= {26,64,85,4,14,35,94,7,5,69};
int mini,maxi;
void maxmin(int i,int j,int &max1,int &min1)
{
    int min2,max2;
    if(i==j)
        max1=min1=l[i];
    else if(i==j-1)
    {
        if(l[i]<l[j])
        {
            max1=l[j];
            min1=l[i];
        }
        else
        {
            max1=l[i];
            min1=l[j];
        }
    }
    else
    {
        int m=(i+j)/2;
        maxmin(i,m,max1,min1);
        maxmin(m+1,j,max2,min2);
        if(max1<max2)
            max1=max2;
        if(min1>min2)
            min1=min2;
    }
}
int main()
{
    maxmin(0,9,maxi,mini);
    cout<<maxi<<endl;
    cout<<mini<<endl;
    return 0;
}

问题4:分治法青蛙过河

一条小溪尺寸不大,青蛙可以从左岸跳到右岸,在左岸有一石柱L,面积只容得下一只青蛙落脚,同样右岸也有一石柱R,面积也只容得下一只青蛙落脚。有一队青蛙从尺寸上一个比一个小。我们将青蛙从小到大,用1,2,…,n编号。规定初始时这队青蛙只能趴在左岸的石头L上,按编号一个落一个,小的落在大的上面。不允许大的在小的上面。在小溪中有S根石柱,有y片荷叶,规定溪中的柱子上允许一只青蛙落脚,如有多只同样要求按编号一个落一个,大的在下,小的在上,而且必须编号相邻。对于荷叶只允许一只青蛙落脚,不允许多只在其上。对于右岸的石柱R,与左岸的石柱L一样允许多个青蛙落脚,但须一个落一个,小的在上,大的在下,且编号相邻。当青蛙从左岸的L上跳走后就不允许再跳回来;同样,从左岸L上跳至右岸R,或从溪中荷叶或溪中石柱跳至右岸R上的青蛙也不允许再离开。问在已知溪中有S根石柱和y片荷叶的情况下,最多能跳过多少只青蛙?

分析:

本题属于分析推理递推式复杂,而程序编写简单的类型。对于多个变量的问题,首先考虑孤立某个变量,分析其对问题解的影响。

  1. 定义出最多跳过青蛙数量以柱子数量和荷叶数量为变量的函数 Jump(s,y) 。其中: S 为河中柱子数 ;y为荷叶数。
  2. 因为荷叶上仅能停留一只青蛙,柱字上可以停留多只青蛙,所以先考虑孤立出荷叶的变量进行分析,令柱子数量为0。可以较为简单地归纳出Jump(0,y)=y+1。
  3. 接下来考虑河中有1根柱子s1的情况Jump(1,y),前y+1只通过y片荷叶先堆在河中的柱子s1上,后y+1只通过y片荷叶直接堆到对岸的柱子上,最后前y+1只从河中的柱子s1,通过y片荷叶堆到对岸的柱子上,所以最多能跳过2*(y+1)只青蛙,即Jump(1,y)=2*(y+1)。
  4. 暂时没有观察出什么,继续考虑河中有2根柱子s1和s2的情况Jump(2,y),根据前文分析,前2*(y+1)只青蛙可以借助柱子s1与y片荷叶先堆在柱子s2上,后2*(y+1)只青蛙可以借助柱子s1与y片荷叶直接堆在对岸的柱子上,最后前2*(y+1)只青蛙从柱子s2借助s1与y片荷叶堆到对岸的柱子上。综上最多能跳过4*(y+1)只青蛙,即Jump(2,y)=4*(y+1)。
  5. 至此,可以归纳得出,每多一根柱子,最多能跳过的青蛙数量是原来的两倍,最终得出递推式Jump(s,y)=2*(s-1,y)。边界条件为s=0时,Jump(0,y)=y+1。

经过上述分析,编写代码异常简单,代码如下:

#include<stdio.h>
int   Jump(int  S,   int  y)
{
        if(S  ==  0)    return( y + 1 );
        return( 2 * Jump(S-1,  y));
}

int  main( )
{
        int   S,  y;
        printf("请输入石柱和荷叶的数目:");
        scanf("%d %d",   &S,   &y);
        printf("最多有 %d 只青蛙过河\n",  Jump(S, y));
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WYF19999

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值