• 三个水桶等分8升水的问题


    问题描述:

    有三个容积分别为8升、5升、3升的水桶,其中容积为8升的水桶盛满了水,容积为5升和3升的水桶都是空的。三个水桶都没有刻度,现在需要将水桶中的8升水等分成2份,每份都是4升水。条件是只能使用这三个水桶,不能借助其他工具。

    问题分析:

    对于这个问题,似乎没有“规律”可循,没有专门的算法来求解,因此只能尝试使用“穷举法”来求解。

    把每个状态下三个水桶中的水的体积作为status,例如status = array(8,0,0),想要得到的status = array(4,4,0)。

    这样,就把问题转化为“寻径”问题了。只需要找到status = array(8,0,0)转化到status = array(4,4,0)的“路径”即可。

    对于status有如下限制:
    0 <= status[0] <= 8;
    0 <= status[1] <= 5;
    0 <= status[2] <= 3;

    在搜寻sub_status的过程中,要注意sub_status不能和current_status和其祖先相等,要不然程序会进入“环路”。一般的,current_status可以得到好几个sub_status, 如果sub_status和current_status和其祖先的其中一个相等,则忽略这个sub_status。

    一共有三个水桶,则可能的“倒水”动作共有6种(3中取2的全排列),但是在不同的status下,这6种倒水动作中有一些是不可用:①从某一个桶中倒水,但是这个桶是空的,②向某一个桶中倒水,但是这个桶已经满了。

    程序设计:

    按照上面的分析,可以构造一个status类:
    status 类有四个protected 字段:
    _values 值, 例如array(8,0,0)
    _limit 限制, 这里是array(8,5,3)
    _children 用来保存本对象的所有sub_status的values
    _ancestors 用来保存对象本身的values和祖先的values

    程序的大体思路是实例化第一个status——array(8,0,0),在构造函数中搜索sub_status、筛选sub_status,然后实例化所有的sub_status,如果sub_status等于array(4,4,0)则停止实例化,并将_ancestors输出,这样就可以将所有的“路径”找出。

    程序示例(php):

    面向对象风格

     1 <?php
     2 //path: document-root/obj/Status.php
     3 
     4 class Status
     5 {
     6     protected $_values;
     7     protected $_limit;
     8     protected $_children;
     9     protected $_ancestors;
    10 
    11     public function __construct(array $values, array $limit, array $ancestors)
    12     {
    13         $this->_values = $values;
    14         $this->_limit = $limit;
    15         $ancestors[] = $this->_values;
    16         $this->_ancestors = $ancestors;
    17 
    18         $this->generateChildren();
    19     }
    20 
    21     protected function generateChildren()
    22     {
    23         $children = array();
    24 
    25         for($i=0;$i<count($this->_values);$i++){
    26             for($o=$i+1;$o<count($this->_values);$o++){
    27                 $child = $this->turnStatus($i, $o);
    28                 if($child === array(4,4,0)){
    29                     $this->showResult($child);
    30                 }
    31                 if($child !== false && !$this->isAncestor($child) && $child !== array(4,4,0)){
    32                     $children[] = new Status($child, $this->_limit, $this->_ancestors);
    33                 }
    34 
    35                 $child = $this->turnStatus($o, $i);
    36                 if($child === array(4,4,0)){
    37                     $this->showResult($child);
    38                 }
    39                 if($child !== false && !$this->isAncestor($child) && $child !== array(4,4,0)){
    40                     $children[] = new Status($child, $this->_limit, $this->_ancestors);
    41                 }
    42             }
    43         }
    44         $this->_children = $children;
    45     }
    46 
    47     protected function isAncestor($value)
    48     {
    49         foreach ($this->_ancestors as $ancestor) {
    50             if($value === $ancestor){
    51                 return true;
    52             }
    53         }
    54         return false;
    55     }
    56 
    57     protected function turnStatus($i, $o)
    58     {
    59         $value = $this->_values;
    60         if($this->_values[$o] == 0){
    61             return false;
    62         }
    63 
    64         if($this->_values[$i] == $this->_limit[$i]){
    65             return false;
    66         }
    67         if(($this->_limit[$i] - $this->_values[$i]) <= $this->_values[$o]){
    68             $m = $this->_limit[$i] - $this->_values[$i];
    69         }else{
    70             $m = $this->_values[$o];
    71         }
    72 
    73         $value[$o] -= $m;
    74         $value[$i] += $m;
    75         return $value;
    76     }
    77 
    78     protected function showResult(array $child)
    79     {
    80         $path = $this->_ancestors;
    81         $path[] = $child;
    82         //print_r($path);
    83         Register::append('final_status', $path);
    84         //echo "<br/>";
    85     }
    86 }
     1 <?php
     2 //path: document-root/main.php
     3 
     4 require_once("obj/Status.php");
     5 require_once("Register.php");
     6 echo '<pre>';
     7 
     8 $status = new Status(array(8, 0, 0), array(8, 5, 3), array());
     9 
    10 
    11 //var_dump($status);
    12 
    13 $paths = Register::registry('final_status');
    14 printf("共找出 %d 种不同的方式", count($paths));
    15 
    16 $stepNum = 0;
    17 foreach ($paths as $key => $path) {
    18     if($key == 0){
    19         $stepNum = count($path);
    20     }
    21     $_stepNum = count($path);
    22     if($_stepNum < $stepNum){
    23         $stepNum = $_stepNum;
    24         $_key = $key;
    25     }
    26 }
    27 printf(" 其中,第 %d 种方式所用步数最少,为 %d 步", $_key, $stepNum-1);
    28 print_r($paths);
     1 <?php
     2 //path: document-root/Register.php
     3 
     4 class Register
     5 {
     6     static protected $_data = array();
     7 
     8 
     9     public function __construct()
    10     {
    11     }
    12 
    13     static public function register($key, $value)
    14     {
    15         self::$_data[$key] = $value;
    16     }
    17 
    18     static public function append($key, $value)
    19     {
    20         self::$_data[$key][] = $value;
    21     }
    22 
    23     static public function registry($key)
    24     {
    25         if(isset(self::$_data[$key])){
    26             return self::$_data[$key];
    27         }
    28         return null;
    29     }
    30 }

     将上面贴出来的程序按目录放在网站根目录下,访问 main.php 即可得到问题解答。

    过程化风格:

     1 <?php
     2 //file: document-root/index.php
     3 echo '<pre>';
     4 
     5 $limit = array(8,5,3);
     6 $current = array(
     7     'value' => array(8,0,0),
     8     'ancestors' => array(
     9     )
    10 );
    11 $records = array();
    12 $tree = getChildren($current, $limit, $records);
    13 print_r($records);
    14 
    15 
    16 /**
    17  * @param $current array('value', 'children', 'ancestors')
    18  * @param array $limit
    19  * @param array $records
    20  * @return array
    21  */
    22 function getChildren($current, array $limit, array &$records)
    23 {
    24     $children = array();
    25     $pValue = $current['value'];
    26 
    27     for($i=0;$i<count($pValue);$i++){
    28         for($o=$i+1;$o<count($pValue);$o++){
    29 
    30             $child = turn($i, $o, $pValue, $limit);
    31             if($child !== false && !isAncestor($current, $child)){
    32                 $children[] = $child;
    33             }
    34 
    35             $child = turn($o, $i, $pValue, $limit);
    36             if($child !== false && !isAncestor($current, $child)){
    37                 $children[] = $child;
    38             }
    39         }
    40     }
    41 
    42     foreach ($children as $key => $child) {
    43         $current['children'][$key]['value'] = $child;
    44 
    45         $ancestors = $current['ancestors'];
    46         $ancestors[] = $pValue;
    47         $current['children'][$key]['ancestors'] = $ancestors;
    48 
    49         if($child !== array(4,4,0)){
    50             $current['children'][$key]['children'] = getChildren($current['children'][$key], $limit, $records);
    51         }else{
    52             $_records = $ancestors;
    53             $_records[] = $child;
    54             $records[] = $_records;
    55         }
    56     }
    57     return $current;
    58 }
    59 
    60 /**
    61  * @param $i
    62  * @param $o
    63  * @param $value array
    64  * @param $limit
    65  * @return bool|array
    66  */
    67 function turn($i, $o, $value, $limit)
    68 {
    69     if($value[$o] == 0){
    70         return false;
    71     }
    72 
    73     if($value[$i] == $limit[$i]){
    74         return false;
    75     }
    76     if(($limit[$i] - $value[$i]) <= $value[$o]){
    77         $m = $limit[$i] - $value[$i];
    78     }else{
    79         $m = $value[$o];
    80     }
    81 
    82     $value[$o] -= $m;
    83     $value[$i] += $m;
    84     return $value;
    85 }
    86 
    87 function isAncestor(array $current, array $child)
    88 {
    89     $ancestors = $current['ancestors'];
    90     if(in_array($child, $ancestors)){
    91         return true;
    92     }
    93     return false;
    94 }

    在浏览器中直接访问这个文件即可。

  • 相关阅读:
    数据库版本管理工具flyway
    spring webapp的配置文件放置在项目外的方法
    logback
    linux as4 bind9 设置进程中的一些小效果
    设置/勾销Debian的屏保
    Linux内存:内存管理的天禀
    用YUM晋级CentOS体系中PHP和MySQL
    solaris的故事
    Solaris 的防火墙ipfilter设置
    mysql安置设置文件的成绩
  • 原文地址:https://www.cnblogs.com/jpdoutop/p/5765728.html
Copyright © 2020-2023  润新知