博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【智力题】过桥问题和倒水问题
阅读量:4569 次
发布时间:2019-06-08

本文共 4946 字,大约阅读时间需要 16 分钟。

原文:

过桥问题和倒水问题都是笔试面试中的热门智力题,不但微软、GOOGLE、百度、腾讯等公司采用,甚至在IQ测试与公务员考试中都能见到。本文不但教你如何快速用手算来解决这两种问题,并且教你如何用程序代码来计算这两种问题。绝对让你大有收获。

一.过桥问题

在漆黑的夜里,四位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,大家是无论如何也不敢过桥去的。不幸的是,四个人一共只带了一只手电筒,而桥窄得只够让两个人同时通过。如果各自单独过桥的话,四人所需要的时间分别是1258分钟;而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间。问题是,你如何设计一个方案,让用的时间最少。

这个题目被微软、GOOGLE、百度、华硕、建设银行等很多公司用作笔试题或面试题。当然也有用在IQ测试中。

解答其实也容易,能者多劳这四个字就足以形容解答方案了——用时短的人必须要多跑几趟以便传递手电筒。

设这四个人叫做ABCD,他们所需要的时间分别是1258分钟。

第一步:AB过桥,花费2分钟。

第二步:A回来,花费1分钟。

第三步:CD过桥,花费8分钟。

第四步:B回来,花费2分钟。

第五步:AB过桥,花费2分钟。

这样只要花费2+1+8+2+2=15分钟,下面再来考虑如何用程序来解决这类问题,在写程序之前还有个细节要考虑下,比如ABCD四个人所需要的时间分别是18910分钟。

方案一

第一步:AB过桥,花费8分钟。

第二步:A回来,花费1分钟。

第三步:CD过桥,花费10分钟。

第四步:B回来,花费8分钟。

第五步:AB过桥,花费8分钟。

一共要8+1+10+8+8=35分钟。

方案二

第一步:AB过桥,花费8分钟。

第二步:A回来,花费1分钟。

第三步:AC过桥,花费9分钟。

第四步:A回来,花费1分钟。

第五步:AD过桥,花费10分钟。

一共要8+1+9+1+10=29分钟。

因此可以得出更加细化的解决方案——要么是最快者将最慢的2个送过桥,要么是最快的2个将最慢的2个送过桥。即将过桥的人按其过桥的时间从小到大排列,设为AB,…… YZ。其中AB是最快的二个,YZ是最慢的二个。那么就有二种方案:

方案一 最快者将最慢的2个送过桥

第一步:AZ过桥,花费Z分钟。

第二步:A回来,花费A分钟。

第三步:AY过桥,花费Y分钟。

第四步:A回来,花费A分钟。

这四步后总人数就减小2个,花费时间为A + A + Y + Z分钟。

方案二 最快的2个将最慢的2个送过桥

第一步:AB过桥,花费B分钟。

第二步:A回来,花费A分钟。

第三步:YZ过桥,花费Z分钟。

第四步:B回来,花费B分钟。

这四步后总人数同样减小2个,花费时间为A + B + B + Z分钟。

这样,每次比较一下这二种方案就能将总人数减小2。然后我们再考虑一些边界情况:

有三个人过桥设为ABC(已经排好序,下同)。应该花费A + B + C分钟。

有二个人过桥设为AB。那么肯定是花费B分钟。

有一个人过桥设为A。肯定花费A分钟。

 

//热门智力题 - 过桥问题#include
#include
const int MAXN = 1000;int cmp(const void *x,const void *y){ return *(int *)x-*(int *)y;}int main(){ cout<<"热门智力题 - 过桥问题"<
>n; cout<<"请输入每个人过桥时间,以空格分开"<
>a[i]; qsort(a, n, sizeof(a[0]), cmp); sum = 0; for (i = n - 1; i > 2; i = i - 2) { //最小者将最大2个送走或最小2个将最大2个送走 if (a[0] + a[1] + a[1] + a[i] < a[0] + a[0] + a[i - 1] + a[i]) sum = sum + a[0] + a[1] + a[1] + a[i]; else sum = sum + a[0] + a[0] + a[i - 1] + a[i]; } if (i == 2) sum = sum + a[0] + a[1] + a[2]; else if (i == 1) sum = sum + a[1]; else sum = a[0]; cout<<"最短过桥时间为:"<
<

程序运行结果如下:

 

二.倒水问题

这个题目的版本非常之多,有微软版的,腾讯版的,新浪版的等等,最常见的是给你一个容量为5升的桶和一个容量为3升的桶,水不限使用,要求精确得到4升水。

解法肯定有很多,可以用宽度优先搜索(BFS),也可以用穷举法。穷举法实现比较方便,其基本思想是用:用小桶容量的倍数对大桶的容量进行取余。比如3升的桶和5升的桶得到4升水可以这样做:

3 % 5 = 3

6 % 5 = 1

9 % 5 = 4

成功得到4升水。(PS:上面的过程用如何用文字描述了?)

同样,用7升的桶和11升的桶得到2升水可以这样做:

7 % 11 = 7

14 % 11 = 3

21 % 11 = 10

28 % 11 = 6

35 % 11 = 2

成功得到2升水。

哈哈,有了这个基本思想在用笔算答案时简直是遇神杀神,遇佛杀佛,又方便又快速!如果要求用程序来实现如何做了?easy,将倒水问题的基本思想用易于编程的话来翻译下——不断用小桶装水倒入大桶,大桶满了立即清空,每次判断下二个桶中水的容量是否等于指定容量。有了这个倒水问题的编程指导方针后代码非常容易写出:

 

//热门智力题 - 打水问题//基本思想:用小桶容量的倍数对大桶的容量进行取余。//指导方针:不断用小桶装水倒入大桶,大桶满了立即清空,//每次判断下二个桶中水的容量是否等于指定容量。#include
#include
#include
using namespace std;const string OPERATOR_NAME[7] = { "装满A桶","装满B桶", "将A桶清空","将B桶清空", "A桶中水倒入B桶","B桶中水倒入A桶", "成功"};int main(){ cout<<"热门智力题 - 打水问题"<
record; //记录操作步数 int ai; int i, a_water, b_water; cout<<"请输入A桶容量,B桶容量,目标容量:"; cin>>a_volume>>b_volume>>goal_volume; a_water = b_water = 0; //A桶,B桶中有多少升水 char szTemp[30]; while (true) { if (a_water == 0)//A桶没水,就装满水 { a_water = a_volume; sprintf(szTemp, " A:%d B:%d", a_water, b_water); record.push_back(OPERATOR_NAME[0] + szTemp);//fill A } else { //如果A桶的水比(B桶容量-B桶的水)要多 if (a_water > b_volume - b_water) { //A桶的水==A桶的水+B桶的水-B桶容量 a_water = a_water + b_water- b_volume; b_water = b_volume; //B桶的水装满了 sprintf(szTemp, " A:%d B:%d", a_water, b_water); record.push_back(OPERATOR_NAME[4] + szTemp);//A->B if (a_water == goal_volume) break; b_water = 0; //将B桶清空 sprintf(szTemp, " A:%d B:%d", a_water, b_water); record.push_back(OPERATOR_NAME[3] + szTemp); } else { //B桶的水==A桶的水+B桶的水 b_water += a_water; a_water = 0; sprintf(szTemp, " A:%d B:%d", a_water, b_water); record.push_back(OPERATOR_NAME[4] + szTemp);//A->B if (b_water == goal_volume) break; } } } record.push_back(OPERATOR_NAME[6]); //success cout<<"\n---------------------------------------------------"<
::iterator pos; for (pos = record.begin(); pos != record.end(); pos++) cout<<*pos<

程序运行结果如下:

 

注意这里只是给出一个可行的倒水方案,不一定是最优解。另外倒水问题要注意下像2升的桶和4升的桶得到3升水这种不可解的情况,这种不可解情况在用本文中对倒水问题所总结的基本思想计算时会得到循环数列。其根本原因是二个桶容量的最大公约数无法被目标容量所整除,如6升的桶和9升的桶无法得到2升水是因为69的最大公约数是3GCD(69)=33无法整除2

倒水问题也也容易推广到多个桶的情况,分析方法和上文差不多,这里就不再赘述了。

 

过桥问题和倒水问题就讲解到此,相信以后这二类问题都不会再困扰大家了^_^。

 

 

转载于:https://www.cnblogs.com/theCambrian/p/3474785.html

你可能感兴趣的文章
题目831-签到-nyoj-20140818
查看>>
百词斩-斩家秘籍
查看>>
Mysql主从配置,实现读写分离
查看>>
ES6中的Symbol
查看>>
1.8小结
查看>>
浅谈C#关于AOP编程的学习总结
查看>>
无障碍阅读
查看>>
bzoj1494 生成树计数 (dp+矩阵快速幂)
查看>>
python canvas画移动物体_tkinter – 用于画布对象python的动画移动的方法
查看>>
java 连接 rac_JAVA 连接 ORACLE RAC 字符串
查看>>
java面试题 网络编程_java面试题《三、网络编程》
查看>>
java布尔矩阵程序_Java编程学习摘要(2)语法基础
查看>>
java no wait_即使队列在activemq中不为空,JMS实现中的receiveNoWait也返回null
查看>>
java定义player类_简易扑克牌游戏 定义了Constants、Main、Player、Poker四个类
查看>>
java方法重载例题_Java方法重载实现原理及代码实例
查看>>
java 字符串 包含 次数_用JAVA写查询一个字符串中是否包含另外一个字符串以及出现的次数...
查看>>
java jvm arg_java – Ant,jvmarg,系统属性和引号
查看>>
karp算法Java_Java – 具有Held和Karp算法的旅行推销员
查看>>
Session共享问题---理论
查看>>
Redis键的基本操作
查看>>