计算思维实践之路(二)

          6月15日,晴。布谷鸟叫最愁肠, 收罢山蚕麦又黄。 昨夜一场梅子雨, 催得万家割麦忙。

      例2 猴子吃桃:有一堆桃子不知数目,猴子第一天吃掉一半,觉得不过瘾,又多吃了一只,第二天照此办理,吃掉剩下桃子的一半另加一个,天天如此,到第十天早上,猴子发现只剩一只桃子了,问这堆桃子原来有多少个?

     俺老猪最喜欢吃桃子了,这道题目有点难?但我掰着指头可以算出每一天的剩下的桃子,然后...?疑问

                        第10天......剩余1个桃子;

                        第 9天......剩余4个桃子;

                       第 8天......剩余10个桃子;

                       

     老猪的一贯伎俩就是枚举,碰到比较复杂的问题就很繁琐,能不能找一找规律性的东西?

     老猪光吃不动脑筋,俺沙悟净来捋一捋:

                                       第10天的桃子数:a10=1

                                      第9天的桃子数:a9=2 * ( a10+ 1 );

                                      第8天的桃子数: a8=2 * ( a9+ 1 );

                                        ...

                                      第i天的桃子数:ai=2 * ( ai+1 + 1 );

                  1、任务分析

                   

                   2、流程图

                                                       

              3、代码实现              

/*
ID: xianzws1
PROG: peach
LANG: C++
*/

#include <stdio.h>
#include <ctype.h>

int main() {
	int sum,a[11],i;
	//初始化第十天的桃子数为1
	sum=a[10]=1;

	for( i=9; i>0; i--) {//从第九天起,倒推每一天剩余的桃子数
		a[i]=2*(a[i+1]+1);
		sum =  a[i];
	}
	printf("%d\n",sum);

	return 0;
}

    问题求解一般从初始的一个或若干个数据项出发,通过递推关系逐步推进,从而得到最终结果,这种求 解问题的方法叫“递推法”。其中,初始的若干数据项称为“边界”。

    解决递推问题有三个重点:如何建立正确的递推关系 ? 递推关系有何性质 ? 递推关系式如何求解?

    按照推导问题的方向,递推分为: 逆推法 和 顺推法。

     问题分析: 已知条件第 10 天剩下 1 个桃子,隐含条件每一次前一天的桃子个数等于后一天桃子的个数加 1 的 2 倍。 采取逆向思维的方法,从后往前推,可用逆推法求解。

/*
ID: xianzws1
PROG: peach
LANG: C++
*/

#include <stdio.h>
int main() {
	int a=1,i;
	
	for (i=9; i>=1; i--)
	    a=(a+1)*2;
	printf("%d",a);
	
	return 0;
}

    例3 A、B、C、D、E 五人合伙夜间捕鱼,凌晨时都疲惫不堪,各自在湖边的树丛中找地方睡着了。日上三竿,A第一个醒来,他将鱼平分作五份,把多余的一条扔回湖中,拿自己的一份回家去了。B第二个醒来,也将鱼平分为五份,扔掉多余的一条,只拿走自己的一份。接着  C、D、E 依次醒来,也都按同样的办法分鱼。问五人至少合伙捕到多少条鱼?每个人醒来后看到的鱼数是多少条?

    俺自西海龙王三太子变身为白龙马,皈依佛门,载乘唐僧上西天取经,虽不及猴哥机灵,但也颇通算法,俺来分析一下此题。

         问题分析:

               假定A、B、C、D、E 五人的编号分别为1、2、3、4、5,整数数组 fish[k]表示第 k 个人所看到的鱼数。fish[1] 表示A所看到的鱼数,fish[2] 表示 B 所看到的鱼数……

        fish[1] A所看到的鱼数,合伙捕到鱼的总数   

         fish[2]=(fish[1]-1)*4/5  B所看到的鱼数

         fish[3]=(fish[2]-1)*4/5  C所看到的鱼数

         fish[4]=(fish[3]-1)*4/5   D所看到的鱼数

         fish[5]=(fish[4]-1)*4/5     E 所看到的鱼数

        写成一般式

              fish [ i   ] = ( fish [ i  - 1 ] – 1 ) * 4 /5                       i = 2, 3, …,5

        这个公式可用于知A 看到的鱼数去推算 B 看到的,再推算 C 看到的,…….。现在要求的是 A 看到的。能否倒过来,先知 E 看到的再反推 D 看到的,……,直到A看到的。为此将上式改写为:

            fish[ i-1 ] = fish[i ] * 5 / 4 +1            i = 5, 4,…,2

         分析上式      

       1. 当 i= 5 时,fish[5 ] 表示 E醒来所看到的鱼数,该数应满足被5整除后余1,即

                 fish[5 ] % 5  ==  1

        2. 当 i= 5 时,fish[i-1 ] 表示 D醒来所看到的鱼数,这个数既要满足

                 fish[4 ] = fish[ 5 ] * 5 / 4 + 1                又要满足

                 fish[4 ] % 5 == 1

                显然,fish[ 4 ] 不能不是整数,这个结论同样可以用至 fish[ 3 ], fish[ 2 ] 和fish[ 1 ]

          3 . 按题意要求 5 人合伙捕到的最少鱼数,可以从小往大枚举,可以先让E 所看到的鱼数最少为 6 条,即 fish[ 5 ] 初始化为 6 来试,之后每次增加 5 再试,直至递推到 fish[ 1 ] 得整数且除以 5 之后的余数为 1。  

        根据上述思路,我们可以构思如下的程序框图:

     

     该图可分为三部分        

      (1)是说明部分:包含定义数组fish[6],并初始化为 1 和定义循环控制变量 i,并初始化为 0。

      (2)是do….while 直到型循环,其循环体又含两块:

            (2).1是枚举过程中的fish[5] 的初值设置,一开始 fish[5]=1+5; 以后每次增5。

            (2).2是一个for 循环,i的初值为 4,终值为 1,步长为 -1,该循环的循环体是一个分支语句,如果fish[i+1]不能被 4 整除(因为fish[ i+1 ] * 5 / 4 + 1必定是整数
),则跳出 for 循环(使用 break 语句;)否则,从 fish[i+1] 算出fish[i]。

           当由break 语句让程序退出循环时,意味着某人看到的鱼数不是整数,当然不是所求,必须令fish[ 5 ] 加 5 后再试,即重新进入直到型循环  do   while 的循环体。

           当着正常退出for 循环时,一定是控制变量  i从初值 4,一步一步执行到终值 1,每一步的鱼数均为整数,最后 i= 0,表示计算完毕,且也达到了退出直到型循环的条件。

      (3)输出计算结果   

/*
ID: xianzws1
PROG: fish
LANG: C++
*/

#include <iostream>	   // 预编译命令
using namespace std;
int  main() {	   //主函数
	int fish[6]= {1,1,1,1,1,1}; // 整型数组,记录每人醒来后看到的鱼数
	int i=0;
	do {
		fish[5]=fish[5]+5;          // 让E看到的鱼数增5。
		for (i=4; i>=1; i--) {
			if ( fish[i+1]%4 !=0 )
				break;	    // 跳出for循环
			else
				fish[i]=fish[i+1]*5/4+1;// 计算第i人看到的鱼数
		}
	} while( i>=1 ); // 当 i>=1 继续做do循环
	// 输出计算结果
	for (i=1; i<=5; i++)
		cout << fish[i] << endl;
	return 0;
}

 例4:猴子分食桃子 五只猴子采得一堆桃子,猴子彼此约定隔 天早起后再分食。不过,就在半夜里,一只猴 子偷偷起来,把桃子均分成五堆后,发现还多 一个,它吃掉这桃子,并拿走了其中一堆。第 二只猴子醒来,又把桃子均分成五堆后,还是 多了一个,它也吃掉这个桃子,并拿走了其中 一堆。第三只,第四只,第五只猴子都依次如 此分食桃子。那么桃子数最少应该有几个呢?

嘿嘿,俺土地公也模仿写一个

/*
ID: xianzws1
PROG: monkey
LANG: C++
*/

#include <stdio.h>
int main() {
	int x,s,k,i;
	x=6; //第五只猴子面前最少的桃子数
	k=0; //整除标志
	while ( k!=4) {
		s=x;
		k=0;
		for ( i=4; i>=1; i--) {
			if ( s%4 ==0) k++;
			else break;
			s=s*5/4+1;
		}
		x=x+5;
	}
	printf("s=%d\n",s);
	return 0;
} 
土地佬儿还真不赖 大笑






  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值