热门智力题 过桥问题和倒水问题

过桥问题与倒水问题的高效算法解析与程序实现
本文深入解析过桥问题与倒水问题的解题策略,提供快速的手动求解方法及程序代码实现,旨在帮助读者理解和掌握这些问题的解决技巧。文章详细介绍了过桥问题的最优方案、程序代码编写方法,以及倒水问题的基本思想与编程指导方针,包括如何通过取余运算快速获得所需水量。同时,提供了实际的代码示例和运行结果,使读者能够直观理解并实践这些算法。

过桥问题和倒水问题都是笔试面试中的热门智力题,不但微软、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分钟。

分析至此,代码很容易写出,对输入的数据可以用快速排序来排下序(关于qsort的使用,可以参见《使用VC库函数中的快速排序函数》)。

  1. //热门智力题-过桥问题
  2. #include<iostream.h>
  3. #include<stdlib.h>
  4. constintMAXN=1000;
  5. intcmp(constvoid*x,constvoid*y)
  6. {
  7. return*(int*)x-*(int*)y;
  8. }
  9. intmain()
  10. {
  11. cout<<"热门智力题-过桥问题"<<endl;
  12. cout<<"--byMoreWindows(http://blog.youkuaiyun.com/MoreWindows)--\n"<<endl;
  13. intn,i,sum,a[MAXN];
  14. cout<<"请输入人数:";
  15. cin>>n;
  16. cout<<"请输入每个人过桥时间,以空格分开"<<endl;
  17. for(i=0;i<n;i++)
  18. cin>>a[i];
  19. qsort(a,n,sizeof(a[0]),cmp);
  20. sum=0;
  21. for(i=n-1;i>2;i=i-2)
  22. {
  23. //最小者将最大2个送走或最小2个将最大2个送走
  24. if(a[0]+a[1]+a[1]+a[i]<a[0]+a[0]+a[i-1]+a[i])
  25. sum=sum+a[0]+a[1]+a[1]+a[i];
  26. else
  27. sum=sum+a[0]+a[0]+a[i-1]+a[i];
  28. }
  29. if(i==2)
  30. sum=sum+a[0]+a[1]+a[2];
  31. elseif(i==1)
  32. sum=sum+a[1];
  33. else
  34. sum=a[0];
  35. cout<<"最短过桥时间为:"<<sum<<endl;
  36. return0;
  37. }

程序运行结果如下:

二.倒水问题

这个题目的版本非常之多,有微软版的,腾讯版的,新浪版的等等,最常见的是给你一个容量为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,将倒水问题的基本思想用易于编程的话来翻译下——不断用小桶装水倒入大桶,大桶满了立即清空,每次判断下二个桶中水的容量是否等于指定容量。有了这个倒水问题的编程指导方针后代码非常容易写出:

  1. //热门智力题-打水问题
  2. //基本思想:用小桶容量的倍数对大桶的容量进行取余。
  3. //指导方针:不断用小桶装水倒入大桶,大桶满了立即清空,
  4. //每次判断下二个桶中水的容量是否等于指定容量。
  5. #include<iostream>
  6. #include<vector>
  7. #include<string>
  8. usingnamespacestd;
  9. conststringOPERATOR_NAME[7]={
  10. "装满A桶","装满B桶",
  11. "将A桶清空","将B桶清空",
  12. "A桶中水倒入B桶","B桶中水倒入A桶",
  13. "成功"
  14. };
  15. intmain()
  16. {
  17. cout<<"热门智力题-打水问题"<<endl;
  18. cout<<"--byMoreWindows(http://blog.youkuaiyun.com/MoreWindows)--\n"<<endl;
  19. inta_volume,b_volume,goal_volume;
  20. vector<string>record;//记录操作步数
  21. intai;
  22. inti,a_water,b_water;
  23. cout<<"请输入A桶容量,B桶容量,目标容量:";
  24. cin>>a_volume>>b_volume>>goal_volume;
  25. a_water=b_water=0;//A桶,B桶中有多少升水
  26. charszTemp[30];
  27. while(true)
  28. {
  29. if(a_water==0)//A桶没水,就装满水
  30. {
  31. a_water=a_volume;
  32. sprintf(szTemp,"A:%dB:%d",a_water,b_water);
  33. record.push_back(OPERATOR_NAME[0]+szTemp);//fillA
  34. }
  35. else
  36. {
  37. //如果A桶的水比(B桶容量-B桶的水)要多
  38. if(a_water>b_volume-b_water)
  39. {
  40. //A桶的水==A桶的水+B桶的水-B桶容量
  41. a_water=a_water+b_water-b_volume;
  42. b_water=b_volume;//B桶的水装满了
  43. sprintf(szTemp,"A:%dB:%d",a_water,b_water);
  44. record.push_back(OPERATOR_NAME[4]+szTemp);//A->B
  45. if(a_water==goal_volume)
  46. break;
  47. b_water=0;//将B桶清空
  48. sprintf(szTemp,"A:%dB:%d",a_water,b_water);
  49. record.push_back(OPERATOR_NAME[3]+szTemp);
  50. }
  51. else
  52. {
  53. //B桶的水==A桶的水+B桶的水
  54. b_water+=a_water;
  55. a_water=0;
  56. sprintf(szTemp,"A:%dB:%d",a_water,b_water);
  57. record.push_back(OPERATOR_NAME[4]+szTemp);//A->B
  58. if(b_water==goal_volume)
  59. break;
  60. }
  61. }
  62. }
  63. record.push_back(OPERATOR_NAME[6]);//success
  64. cout<<"\n---------------------------------------------------"<<endl;
  65. cout<<"一个可行的倒水方案如下"<<endl;
  66. vector<string>::iteratorpos;
  67. for(pos=record.begin();pos!=record.end();pos++)
  68. cout<<*pos<<endl;
  69. cout<<"---------------------------------------------------"<<endl;
  70. return0;
  71. }

程序运行结果如下:

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

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

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

转载请标明出处,原文地址:http://blog.youkuaiyun.com/morewindows/article/details/7481851

<think>好的,用户需要寻找关于倒水智力题数学问题脑筋急转弯。首先,我需要明确用户的需求,可能他们是在寻找一些有趣的逻辑题或者数学问题来挑战自己或者用于教学等场景。接下来,我需要调用网络搜索工具,查找相关的经典倒水问题。 根据常见的智力题倒水问题通常涉及用不同容量的容器量出特定量的水。例如,3升5升的桶如何得到4升水,这类问题比较经典。可能还需要考虑其他变种,比如没有刻度的情况下如何操作,或者更复杂的步骤。另外,脑筋急转弯类型的题目可能需要更巧妙的解答,比如利用环境因素或其他容器。 在整合信息时,需要确保每个问题都有清晰的描述解答步骤,并且按照用户的要求分点说明,避免使用步骤词汇。同时,要注意数学公式代码的格式规范,如果有的话。例如,涉及到数学表达式时,需要用$符号包裹。 还需要检查是否有其他类型的倒水问题,比如涉及多个容器的,或者需要最少步骤解决的。此外,脑筋急转弯可能需要非传统的解决方法,比如改变容器的形状或利用其他物理特性。 最后,生成相关问题部分时,要基于用户的原问题,可能涉及具体问题的解法、变种题目或数学理论。例如,如何用7升11升得到2升,或者这类问题的最优解算法,以及相关的数学理论。 总结时,确保回答结构清晰,分方法或步骤,每个部分换行,并且最后的问题部分符合格式要求,使用正确的标题编号,没有多余的空格或换行。</think>通过搜索整合倒水智力题的经典案例解法,以下是三个典型类型及解决方法: 一、标准量水问题(3L+5L→4L) 给定3升5升空桶,5升桶装满水。将5升桶的水倒入3升桶至满,剩余2升在5升桶。倒空3升桶后,将5升桶的2升水转移至3升桶。再次注满5升桶,用其将3升桶补满(此时3升桶已有2升),5升桶剩下4升。数学表达为:$5 - (3 - (5 - 3)) = 4$ 二、无刻度容器问题(8L容器取6L) 装满8升容器,倒入5升容器至满。倒空5升容器,将8升容器剩余的3升转移至5升容器。再注满8升容器,用其将已有3升的5升容器补满,最终8升容器剩下$8 - (5 - 3) = 6$升 三、脑筋急转弯型(半满杯判定) 当两个不同形状的杯子都装半满水时,可通过倾斜法判断:将杯子倾斜至水面同时接触杯口杯底边缘,若水面呈对角线状态则为精确半杯。此方法利用几何原理:圆柱体倾斜时水面保持水平,当对角线分割时容积恰为一半,体积公式为$\frac{1}{2}πr^2h$ ```python # 贝祖定理验证水量可行性 def can_measure(a, b, target): import math gcd = math.gcd(a, b) return target % gcd == 0 print(can_measure(3,5,4)) # 输出True ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值