转载博客:http://www.cnblogs.com/webary/p/4827688.html

吃豆子过桥问题

  本题来自于百度校招面试题,通过一个简单的智力问题理解递归问题的解法。

  一:问题描述

  一个人要过一座80米的桥,每走一米需要吃一颗豆子,他最多可以装60颗豆子,问最少需要吃多少颗豆子才能走完桥?

  二:初步分析

  1.一趟(不折回)最多只能走60米豆子就会被吃完;

  2.如果有折回,必须保证能够返回到有豆子的地点,且在折回点放下的豆子尽量多;

  3.尽可能少的折回(次数和折回的距离都要少,毕竟一趟折回就要多消耗一个来回的豆子);

  4.折回点的豆子数量要求至少能够走完剩余的部分;

  三:具体分析

  1.由条件1得一趟走不完,由条件3我们可以考虑折回尽量少的次数能否走完。

  先考虑只折回一次,那么此时就要求得折回点的位置。

  2.由条件3得折回的距离尽量短,那么可以考虑最短的折回距离,很明显应该是20米处;设折回点距离起始位置x米,则此时x=20;那么在x处,需要至少有60颗豆子,一次性拿60颗豆子走完最后一程。

  那么问题就来了,怎么在x处囤积60颗豆子呢,假使他第一次信心满满的拿着60颗豆子,走到x处就只剩下40颗了,现在不够走完剩余的全程啊,只能放下一部分折回去再取了,那放多少呢,很明显由条件2得我们需要放下20颗,拿着20颗刚好可以折回到起点,继续拿着60颗豆子第二次来到x处,此时手上还有40颗,再捡起第一次放的20颗,共60颗豆子刚好可以走完全程。

  在这种情况下,我们易知,他共走了(20)*3+(60)= 120米,故吃掉120颗豆子。

  四:问题拓展

  如果桥长81米呢?

  此时我们如果还是只折回一次的话,在21米处还是得有60颗豆子,也就是需要搬运60颗豆子到21米处;分析得不可能只折回一次就搬运60颗豆子到21米处,因此需要再设置一个折返点y,此时x=21,0<y<x;

  刚才考虑了80米的情况,那么我们可以假设现在在80米的基础上加了1米,因此可以设y=1,即先折回两趟到1米处,这样y处就有60*3-5*(1)=175颗豆子,再从y到x折返1趟,x处就有60*2-3*(20)=60颗豆子,最后从x出发拿着60颗豆子就可以愉快的走过桥了。

  因此他共走过5*(1)+3*(20)+(60) = 125米,故吃掉125颗豆子。

  五:再次拓展

  如果桥长n米,最多装m颗豆子,最少消耗f(n,m)与n和m的关系是什么呢?

  此时问题突然就变得很复杂了,别急,我们分析一下刚才的思路,桥长从80米到81米,就是要在1米处放足够多豆子(当然只要不小于桥长80米时的消耗就行),那么这些豆子又需要从起点处运到1米处,那么在这1米内又需要消耗多少豆子呢?

  我们可以考虑先把可装的最大豆子数m固定(假设还是60),当桥长0<n<=60米时,f(n,m) = n;

  当n=61时,需要在1米处囤积f(n-1,6)即f(60,60)=60颗豆子,囤积过程中需要往返一次,第一次到达1米处留下58颗豆子赶紧回去再取60颗到达1米处还剩59颗,现在有117颗足够走完最后60米。消耗豆子1*2+(1)+60 = 63颗豆子;

  当n=62时,需要在1米处囤积f(n-1,m)即f(61,60)=63颗豆子,囤积过程中需要往返一次,第一次到达1米处留下58颗豆子赶紧回去再取60颗到达1米处还剩59颗,现在有117颗足够走完最后61米。消耗豆子1*2+(1)+63 = 66颗豆子;

  以此类推...

  那么问题来了,细心的你肯定发现了上面那种情况都是往返一次的,但是不是每次都只往返一次,比如当n=81时,该怎么确定往返的次数呢?

  分析上面的递推关系我们可以知道,每次往返的趟数与f(n-1,m)的大小有关。分析往返过程易知:最后一次到达1米处剩59颗豆子,之前每次到达1米处可以放下58颗豆子,假设之前到达了1米处T次,则有:

  59 + 58 * T >= f(n-1,60)  ==>  T >= [f(n-1,60)-59]/58

  由于T必须是整数,故T = ceil((f(n-1,60)-59) / 58),ceil(x)表示对x向上取整,即不小于x的最小整数

  另一种表示方式为T = floor( (f(n-1,60)-2) / 58 ),这种写法是为了方便编程实现,整型数的除法会自动向下取整

  之前往返T次消耗掉2T颗豆子,最后一次到达1米处消耗1颗豆子,故总消耗:f(n-1,60) + 2T + 1颗豆子

  这时候我们考虑将固定为60的m扩展为任意m,则有:f(n,m) = f(n-1,m) + ceil( f(n-1,m)-(m-1)) / (m-2) ) * 2+ 1 = f(n-1,m) + (f(n-1,m)-2) / (m-2) * 2+ 1 ;

  好了到这里,这个问题也彻底解决完了,现在就让我们用简短的代码来实现这个过程吧!

  六:编程实现   

 1 #include<cmath>2 #include<iostream>3 using namespace std;4 typedef unsigned long long int64;5 6 //参数说明:length为桥的长度,maxNum为最大可带的豆子数7 //递归实现8 int64 getMinConsume(int length, int maxNum) {9     if(length <= maxNum)
10         return length;
11     int64 get_n_1 = getMinConsume(length-1,maxNum); //上一次的豆子消耗
12     return get_n_1 + (get_n_1-2)/(maxNum-2) * 2 + 1;
13 }
14 //第二种公式实现——递归
15 int64 getMinConsume2(int length, int maxNum) {
16     if(length <= maxNum)
17         return length;
18     int64 get_n_1 = getMinConsume2(length-1,maxNum);  //上一次的豆子消耗
19     return get_n_1 + ceil((double)(get_n_1-maxNum+1)/(maxNum-2)) * 2 + 1;
20 }
21 //非递归的实现方式
22 int64 getMinConsume_NoRecursive(int length, int maxNum) {
23     if(length <= maxNum)
24         return length;
25     int64 result = maxNum, i;
26     for(i=maxNum; i<length; i++)
27         result += (result-2)/(maxNum-2) * 2 + 1;
28     return result;
29 }
30
31 int main()
32 {
33     int maxNum=60, length;
34     for(length=50; length<201; length++)
35         cout<<length<<"米至少消耗"<<getMinConsume2(length,maxNum)<<"颗豆子!"<<endl;
36     return 0;
37 }
38
39 int main2()
40 {
41     while(1){
42         cout<<"请输入最大可带的豆子数量和桥的长度: ";
43         int maxNum, length;
44         if(!(cin>>maxNum>>length))
45             break;
46         cout<<"至少消耗"<<getMinConsume_NoRecursive(length,maxNum)<<"颗豆子!"<<endl;
47     }
48     return 0;
49 }

转载于:https://www.cnblogs.com/zpfbuaa/p/5023363.html

吃豆子过桥问题(转)相关推荐

  1. 《吃豆子过桥问题》——经典智力题、面试题

    转载http://www.cnblogs.com/webary/p/4827688.html?utm_source=tuicool&utm_medium=referral 吃豆子过桥问题 本题 ...

  2. 吃豆豆游戏的C语言程序码,C++实现基于控制台界面的吃豆子游戏

    本文实例讲述了C++实现基于控制台界面的吃豆子游戏.分享给大家供大家参考.具体分析如下: 程序运行界面如下所示: ESC键可退出游戏. main.cpp源文件如下: #include "li ...

  3. C++小项目-吃豆子游戏

    GMap.h #pragma once //保证头文件只被编译一次#include "stdafx.h"#define MAP_LEN 19 //逻辑地图大小 (逻辑地图由行.列各 ...

  4. 手把手教学MFC吃豆子教程

    手把手教学MFC吃豆子教程 本教程适用于零基础学员制作C++课程设计 编程工具:VC++6.0. 本次教学主要知识点: 1.控件消息响应. 2.CDC类函数的使用. 下面开始教学: 吃豆子的基本思想: ...

  5. C++项目实战(二)——简化版 “吃豆子游戏---pacman” 实现

    本项目通过使用 windows 窗口应用程序 实现一个简化版的 吃豆子游戏,主要涉及的知识点包含有:面向对象编程思想.windows 消息循环的工作原理.windows 窗口应用程序实现.父类与子类的 ...

  6. 厉害的程序员都有吊炸天的实力,C++实现吃豆子游戏!

    作为"全世界卖得最多的街机游戏","吃豆人"大家再熟悉不过了.但它是"现代游戏AI鼻祖"这件事,恐怕知道的人不多. 这篇文章主要介绍了C++ ...

  7. 基于JavaSwing开发吃豆子小游戏 课程设计 大作业源码

    基于JavaSwing开发吃豆子小游戏:   (大作业) 开发环境: Windows操作系统 开发工具: MyEclipse/Eclipse/idea+Jdk 运行效果图: 基于JavaSwing开发 ...

  8. c#吃豆子游戏,模仿百度在线应用吃豆子

    这是一款模仿百度在线吃豆子的应用,本人对于C#小游戏制作的理解不是很深.CSDN里面用c#做的吃豆子也实在是太少,有的也太过于简单,于是萌生了一个念头,做一款C#吃豆子游戏,希望互相学习. csdn下 ...

  9. 控制台界面的吃豆子游戏

    ESC键可退出游戏. main.cpp #include "lib.h"#pragma onceextern int level;int main() {FOOD food;WAL ...

最新文章

  1. 66篇论文入选CVPR 2021,商汤的秘籍竟是“大力出奇迹”
  2. Spark源码阅读04-Spark运行架构之Standalone运行模式
  3. python绘制3d图形-Python基于matplotlib实现绘制三维图形功能示例
  4. python数据库查询怎么用变量_python中带变量的SQL查询
  5. WordPress函数:wp_nav_menu($args)函数说明
  6. 【HDU - 3466 】Proud Merchants(dp,背包问题,巧妙排序)
  7. Wo Cloud CentOS 挂载磁盘小计
  8. oracle ogg 12安装,Oracle GoldenGate Studio 12.2.1.3安装
  9. C++头文件<functional>和bind、placeholders占位符使用简单例子
  10. Excel将多个工作簿加载到SQL Server中
  11. android源码中的ndk,如何在不需要Android操作系统源代码的情况下在Android NDK中创建新的NativeWindow?...
  12. Ownership and Permissions
  13. Linux——常用命令
  14. 微信公众平台二次开发技术文档
  15. 小书童开源免费的二维码批量生成工具
  16. 从 Flask-RESTful 到 Flask-RESTPlus 再到 Flask-RESTX
  17. 机械设备网站建设多少钱
  18. WT2003H4-16S 语音芯片按键录音及播放应用解析
  19. 各个排序算法的时间复杂度和稳定性,快排的原理
  20. 基于飞桨本地ocr安卓按键插件

热门文章

  1. websocket系列:基于tio-websocket-spring-boot-starter实现
  2. 网页出现乱码及乱码解决方案
  3. 浏览器查看,请在微信客户端打开链接
  4. iabp使用流程,bpa流程开发
  5. 联想Y50C加内存条
  6. 英语小短文翻译1——The Significance of Books
  7. MOV格式的视频应该如何转换成MP4格式的
  8. PowerMill 2017五轴联动编程视频教程
  9. 示波器测量晶振、万用表测量晶振的方法
  10. ipaddress 模块介绍