`

代码实现任意容量倒水问题

阅读更多

形象化设计模式实战             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升的水的吗?

4
3
分享到:
评论
1 楼 dsjt 2014-11-05  


下载了个应用就是倒水的。

相关推荐

    “倒水”算法代码实现

    总的来说,"倒水"问题的代码实现涉及到数据结构、算法、逻辑推理和程序设计等多个方面,是理解和提升编程思维的良好实践。通过这样的练习,开发者能够锻炼到问题抽象、状态空间建模、搜索策略选择和代码实现等多方面...

    三个容器的倒水问题(C语言实现)

    标题 "三个容器的倒水问题(C语言实现)" 涉及到的是一个经典的算法问题,通常出现在计算机科学的面试或编程挑战中。这个问题的核心是通过使用三个容器来确定如何最大限度地转移水,使得两个容器中的水量之和达到某个...

    倒水问题的解答

    从给定文件中我们可以看到,这是一段关于“倒水问题”的C++代码,它涉及到一些编程技巧和算法思路。接下来,我们将从几个方面来详细介绍这个文件中包含的知识点。 ### 标题和描述知识点 #### 倒水问题 - 倒水问题...

    倒水解密附带源码

    在这款由C#语言实现的倒水解密游戏中,玩家需要通过一系列操作,将不同容量的杯子中的水倒入另一个杯子,使得某个杯子的水量达到特定目标。这个游戏的核心算法是基于状态转移和深度优先搜索(DFS)或广度优先搜索...

    分水问题和倒水问题

    分水问题和倒水问题是一种经典的数学和编程挑战,它涉及到如何通过有限的容器和操作,将一定量的水精确地分成目标体积。在这个特定的问题中,我们需要利用一个8升和一个5升的容器,将12升水分为两个6升。这需要巧妙...

    专家系统水壶倒水问题C#程序

    这个问题涉及到两个不同容量的水壶,一个能装4公斤水,另一个能装3公斤水。目标是通过倒水操作使得4公斤水壶中恰好装有2公斤水。在这个过程中,我们将运用到状态空间法和盲目广度优先搜索算法来解决这个问题。 首先...

    java项目_五五开倒水

    总的来说,"java项目_五五开倒水"是一个结合了基本编程概念与游戏逻辑的实践项目,对于学习Java和提高问题解决能力很有帮助。通过这个项目,开发者可以锻炼到数据结构的选择、算法设计、用户交互以及错误处理等多...

    js实现杯子倒水问题自动求解程序

    JavaScript 实现的“杯子倒水问题自动求解程序”是一种逻辑算法,用于解决常见的智力测试题目,即如何通过几个容量不等的杯子之间的倒水操作,达到特定的水量分配。这种问题通常涉及到策略和数学推理,对编程爱好者...

    OC ioc Xcode三个水杯倒水

    标题“OC ioc Xcode三个水杯倒水”所指的是一个iOS开发的示例项目,主要使用Objective-C(OC)语言,并结合了Inversion of Control(IoC)的设计模式,通过Xcode集成开发环境实现。这个项目的核心是模拟三个水杯之间...

    倒水解密游戏源码2012918

    有N个容量不同的瓶子,指定「将a升水倒入容量为b的瓶子」。 游戏要求通过装水、倒水,达成给定的目标。 游戏操作方式如下: ?在瓶子上双击右键可以把瓶子灌满水 ?双击左键可以把瓶子里的水倒掉 ?将一个瓶子拖动...

    Jugs问题求解C++

    这个问题涉及到两个容量分别为m升和k升的水壶,目标是通过倒水操作使得其中一个水壶装满n升水。题目提供的C++代码正是为了解决这个问题。 在C++代码中,首先定义了两个字符数组a和b,分别代表两个水壶,用'A'表示m...

    野比的倒水解密游戏的C#的源代码

    5. **游戏逻辑**:游戏的核心算法包括水壶的容量计算、倒水规则判断、解谜状态的更新等。这些逻辑通常在C#的类和方法中实现,通过状态机模型管理游戏流程。 6. **数据结构**:可能使用数组、列表或者其他高级数据...

    智能倒水机器人的设计.pdf

    倒水机构用于实现送杯和送水的功能,采用了旋转式送杯的方式,并通过圆盘旋转来实现倒水动作。行走机构则负责机器人在地面的移动,由两个直流无刷电机驱动三个轮子(两个驱动轮和一个从动轮)来保证机器人运动的稳定...

    人工智能 水壶问题的求解.rar

    水壶问题,也被称为“容量问题”或“水量问题”,是人工智能领域中经典的逻辑与算法问题之一。这个问题通常涉及到两个有固定容量的水壶,以及一个精确度目标,要求通过倒水操作找到一种方法,使得某一个水壶的水位...

    控制机器人端盘子倒水的程序设计与实现

    文中提供了一段简化的伪代码示例,详细地描述了从初始化机器人、设定位置、检查水位、执行倒水动作到最后返回目标位置的完整流程。同时强调,在实际操作时需要注意设备的具体硬件环境以及异常情况的处理。 适合人群...

    3d倒水小动画的制作

    自己做的3D倒水是初学者的首选 和容易懂的

    自己写的一些代码

    这些可能是设计的特定问题或小游戏,例如“倒水”可能涉及到容量限制的容器问题,需要解决如何在有限的空间内转移液体;“踩气球”可能是一个模拟游戏,涉及碰撞检测和游戏逻辑;“喝酒”可能是一个简单的计数或...

    comfjshmnp-sec.tar

    两个杯子倒水问题,两个版本解决方案,BFS遍历方式,csdn

    Main_人工智能实验_水壶问题_

    `Main.java`文件很可能是这个算法的实现代码,其中可能包含了对水壶问题的建模、状态遍历和条件判断等关键逻辑。 总的来说,"水壶问题"是一个典型的人工智能实验,它展示了如何运用算法思维解决实际问题。通过这个...

Global site tag (gtag.js) - Google Analytics