形象化设计模式实战 HELLO!架构 redis命令源码解析
倒水问题:有两个杯子,一个A升,一个B升,水有无限多,现要求利用这两杯子装C升的水。
想必很多人都可能被问到过这个问题,问题虽然简单的,但是要费些脑子。这个问题显然是个逻辑问题,那么就肯定能够用程序来实现。
现在我假设A=3,B=5,C=4。
大脑的运算过程:
第一步、把3装满,或把5装满(只有这两种选择吧)。
第二步、把装满的杯子的水倒入空杯子(没有人会把第二个杯子也装满吧)。
第三步、两个杯子的水做运算得出一个D(D不能和A、B相等,如果D等于C就成功啦)
第四步、跟第一步相同
第五步、跟第三步相同
。
。
。
直到D等于C就成功,这个要注意的是D的值不能相同,例如第一次运算得到D=2,如果第三次运算又是2,那就不能再继续下去,不然会无限2,够2的。
将这个过程转为机器逻辑:两个变量a=3,b=5,要使得变量c=4。这好像太简单了,但是注意的是,杯子容量,假设 3+3=6,但实际上杯子装不了6升的水,换作杯子3+3=1,因为5升杯子装满了,多下一升留在3升杯子中。换作逻辑运行就相当于是取余。
代码实现:
<?php /** * 倒水算法 * * @param int $re 目标水位 * @param int $cup1 杯子1的大小 * @param int $cup2 杯子2的大小 * @param int $i 当前杯子有所装水] * @param array $nocan 不能出现的水位,以免死循环 * @return int */ function todo( $re, $cup1, $cup2, $i, $nocan = array() ) { $yu = max( $cup1, $cup2 ); $arr = array( $cup1, $cup2 ); if ( !$nocan ) $nocan = array( 0, $i, $cup1, $cup2 ); foreach ( $arr as $v ) { echo "尝试与{$v}运算\r\n"; //##########做加法################# $tmp = $i + $v; echo "{$i}+{$v}\r\n"; if ( $tmp > $yu ) { $tmp = $tmp%$yu; echo "取{$yu}的余数{$tmp}\r\n"; } if ( $tmp == $re ) { return $tmp; } if ( !in_array( $tmp, $nocan, true ) ) { $nocan[] = $tmp; return todo( $re, $cup1, $cup2, $tmp, $nocan ); }else { echo "failed\r\n"; } //#########做减法################### $tmp = $i - $v; echo "{$i}-{$v}\r\n"; if ( $tmp > $yu ) { $tmp = $tmp%$yu; echo "取{$yu}的余数\r\n"; } if ( $tmp == $re ) { return $tmp; } if ( $tmp > 0 && !in_array( $tmp, $nocan ) ) { $nocan[] = $tmp; return todo( $re, $cup1, $cup2, $tmp, $nocan ); }else { echo "failed\r\n"; } //###########做被减################## $tmp = $v - $i; echo "{$v}-{$i}\r\n"; if ( $tmp > $yu ) { $tmp = $tmp%$yu; echo "取{$yu}的余数\r\n"; } if ( $tmp == $re ) { return $tmp; } if ( $tmp > 0 && !in_array( $tmp, $nocan ) ) { $nocan[] = $tmp; return todo( $re, $cup1, $cup2, $tmp, $nocan ); }else { echo "failed\r\n"; } } return false; }
现在运行todo(4,3,5,3);就是先将3升杯子装满:
尝试与3运算 3+3 取5的余数1 尝试与3运算 1+3
再试下todo(4,3,5,5);先将5升杯子装满:
尝试与3运算 5+3 取5的余数3 failed 5-3 尝试与3运算 2+3 failed 2-3 failed 3-2 尝试与3运算 1+3
代码问题:
1、做加法,如果与A,B较大数做加法,那么是不是相当于没加?
2、做减法,减与被减用绝对值统一处理即可,abs
3、可能有多种倒水方法,而我最想知道的是最快的那种!
优化后代码:
<?php /** * 倒水算法 * * @param int $re 目标水位 * @param int $cup1 杯子1的大小 * @param int $cup2 杯子2的大小 * @param int $i 当前杯子有所装水] * @param array $nocan 不能出现的水位,以免死循环 * @param string $s 倒水过程 * @return int */ function todo( $re, $cup1, $cup2, $i, $nocan = array() , $s ='' ) { global $return,$num; $yu = max( $cup1, $cup2 );//取较大值 $arr = array( $cup1, $cup2 ); if ( !$nocan ) $nocan = array( 0, $i, $cup1, $cup2 ); foreach ( $arr as $v ) { $str = ""; //#########做减法################### $tmp = abs( $i - $v );//这里直接取绝对值 $str .= "{$i}与{$v}相减\r\n"; if ( $tmp > $yu ) { $tmp = $tmp%$yu; $str .= "取{$yu}的余数\r\n"; } if ( $tmp == $re ) { $s .= $str; $num[] = array(substr_count( $s, "\r\n" )); $return[] = array( substr_count( $s, "\r\n" ), $s ); return $tmp; } if ( $tmp > 0 && !in_array( $tmp, $nocan ) ) { $nocan[] = $tmp; $ss = $s.$str; todo( $re, $cup1, $cup2, $tmp, $nocan , $ss ); } $str = ""; //##########做加法################# if ( $yu != $v ) {//跟大杯做加法,相当于白做 $tmp = $i + $v; $str .= "{$i}+{$v}\r\n"; if ( $tmp > $yu ) { $tmp = $tmp%$yu; $str .= "取{$yu}的余数{$tmp}\r\n"; } if ( $tmp == $re ) { $s .= $str; $num[] = array(substr_count( $s, "\r\n" )); $return[] = array( substr_count( $s, "\r\n" ), $s ); return $tmp; } if ( !in_array( $tmp, $nocan, true ) ) { $nocan[] = $tmp; $ss = $s.$str; todo( $re, $cup1, $cup2, $tmp, $nocan , $ss ); } } } return false; } todo( 4, 43, 77, 77 ); if($num && $return){ array_multisort($num, SORT_ASC, $return); print_r(array_slice($return, 0,2));//方法有很多,只打印两种吧 }else{ echo "no way!"; }
Array ( [0] => Array ( [0] => 27 [1] => 77与43相减 34与43相减 9+43 52+43 取77的余数18 18+43 61+43 取77的余数27 27+43 70+43 取77的余数36 36+43 取77的余数2 2+43 45+43 取77的余数11 11+43 54+43 取77的余数20 20+43 63+43 取77的余数29 29+43 72+43 取77的余数38 38+43 取77的余数4 ) [1] => Array ( [0] => 27 [1] => 77与43相减 34与43相减 9+43 52+43 取77的余数18 18+43 61+43 取77的余数27 27+43 70+43 取77的余数36 36+43 取77的余数2 2+43 45+43 取77的余数11 11+43 54+43 取77的余数20 20+43 63+43 取77的余数29 29与77相减 48与43相减 5与43相减 38+43 取77的余数4 ) )
可见最快27步可以搞定!
最后留一个问题:随意A,B升的水,一定能倒出C升的水的吗?
相关推荐
总的来说,"倒水"问题的代码实现涉及到数据结构、算法、逻辑推理和程序设计等多个方面,是理解和提升编程思维的良好实践。通过这样的练习,开发者能够锻炼到问题抽象、状态空间建模、搜索策略选择和代码实现等多方面...
标题 "三个容器的倒水问题(C语言实现)" 涉及到的是一个经典的算法问题,通常出现在计算机科学的面试或编程挑战中。这个问题的核心是通过使用三个容器来确定如何最大限度地转移水,使得两个容器中的水量之和达到某个...
从给定文件中我们可以看到,这是一段关于“倒水问题”的C++代码,它涉及到一些编程技巧和算法思路。接下来,我们将从几个方面来详细介绍这个文件中包含的知识点。 ### 标题和描述知识点 #### 倒水问题 - 倒水问题...
在这款由C#语言实现的倒水解密游戏中,玩家需要通过一系列操作,将不同容量的杯子中的水倒入另一个杯子,使得某个杯子的水量达到特定目标。这个游戏的核心算法是基于状态转移和深度优先搜索(DFS)或广度优先搜索...
分水问题和倒水问题是一种经典的数学和编程挑战,它涉及到如何通过有限的容器和操作,将一定量的水精确地分成目标体积。在这个特定的问题中,我们需要利用一个8升和一个5升的容器,将12升水分为两个6升。这需要巧妙...
这个问题涉及到两个不同容量的水壶,一个能装4公斤水,另一个能装3公斤水。目标是通过倒水操作使得4公斤水壶中恰好装有2公斤水。在这个过程中,我们将运用到状态空间法和盲目广度优先搜索算法来解决这个问题。 首先...
总的来说,"java项目_五五开倒水"是一个结合了基本编程概念与游戏逻辑的实践项目,对于学习Java和提高问题解决能力很有帮助。通过这个项目,开发者可以锻炼到数据结构的选择、算法设计、用户交互以及错误处理等多...
JavaScript 实现的“杯子倒水问题自动求解程序”是一种逻辑算法,用于解决常见的智力测试题目,即如何通过几个容量不等的杯子之间的倒水操作,达到特定的水量分配。这种问题通常涉及到策略和数学推理,对编程爱好者...
标题“OC ioc Xcode三个水杯倒水”所指的是一个iOS开发的示例项目,主要使用Objective-C(OC)语言,并结合了Inversion of Control(IoC)的设计模式,通过Xcode集成开发环境实现。这个项目的核心是模拟三个水杯之间...
有N个容量不同的瓶子,指定「将a升水倒入容量为b的瓶子」。 游戏要求通过装水、倒水,达成给定的目标。 游戏操作方式如下: ?在瓶子上双击右键可以把瓶子灌满水 ?双击左键可以把瓶子里的水倒掉 ?将一个瓶子拖动...
这个问题涉及到两个容量分别为m升和k升的水壶,目标是通过倒水操作使得其中一个水壶装满n升水。题目提供的C++代码正是为了解决这个问题。 在C++代码中,首先定义了两个字符数组a和b,分别代表两个水壶,用'A'表示m...
5. **游戏逻辑**:游戏的核心算法包括水壶的容量计算、倒水规则判断、解谜状态的更新等。这些逻辑通常在C#的类和方法中实现,通过状态机模型管理游戏流程。 6. **数据结构**:可能使用数组、列表或者其他高级数据...
倒水机构用于实现送杯和送水的功能,采用了旋转式送杯的方式,并通过圆盘旋转来实现倒水动作。行走机构则负责机器人在地面的移动,由两个直流无刷电机驱动三个轮子(两个驱动轮和一个从动轮)来保证机器人运动的稳定...
水壶问题,也被称为“容量问题”或“水量问题”,是人工智能领域中经典的逻辑与算法问题之一。这个问题通常涉及到两个有固定容量的水壶,以及一个精确度目标,要求通过倒水操作找到一种方法,使得某一个水壶的水位...
文中提供了一段简化的伪代码示例,详细地描述了从初始化机器人、设定位置、检查水位、执行倒水动作到最后返回目标位置的完整流程。同时强调,在实际操作时需要注意设备的具体硬件环境以及异常情况的处理。 适合人群...
自己做的3D倒水是初学者的首选 和容易懂的
这些可能是设计的特定问题或小游戏,例如“倒水”可能涉及到容量限制的容器问题,需要解决如何在有限的空间内转移液体;“踩气球”可能是一个模拟游戏,涉及碰撞检测和游戏逻辑;“喝酒”可能是一个简单的计数或...
两个杯子倒水问题,两个版本解决方案,BFS遍历方式,csdn
`Main.java`文件很可能是这个算法的实现代码,其中可能包含了对水壶问题的建模、状态遍历和条件判断等关键逻辑。 总的来说,"水壶问题"是一个典型的人工智能实验,它展示了如何运用算法思维解决实际问题。通过这个...