1.问题描述

小孩分油问题

两个小孩去打油,一人带了一个一斤的空瓶,另一个带了一个七两、一个三两的空瓶。原计划各打一斤油,可是由于所带的钱不够,只好两人合打了一斤油,在回家的路上,两人想平分这一斤油,可是又没有其它工具。试仅用三个瓶子(一斤、七两、三两)精确地分出两个半斤油来。

2.算法设计

令状态R、E、S分别表示十两、七两和三两的瓶子中所装的油量。如问题所述,初始时有(R,E,S)=(10,0,0),问题要求即仅通过这三个瓶子,将油量状态转变为(R,E,S)=(5,5,0)。

该问题较为特殊,我们发现七两的瓶子和三两的瓶子所能装的油的总量恰好为十两。因此,我们可以将十两的瓶子等同于一个无穷大的油桶,任何时候七两和三两的瓶子都可以通过这个油桶装满或倒空油。在这个假设下,原问题即被简化为:初始状态(E、S)=(0,0),要求仅通过这两个瓶子,将状态转变为(E、S)=(5,0)。在这个目标状态下,十两的瓶子中自然装了五两油。

将两个瓶子的状态转变以及对应的规则列表如下:

规则号

规则

解释

1

(E,S) and E<7 → (7,S)

7两瓶不满时装满

2

(E,S) and S<3 → (E,3)

3两瓶不满时装满

3

(E,S) and E>0 → (0,S)

7两瓶不空时倒空

4

(E,S) and S>0 → (E,0)

3两瓶不空时倒空

5

(E,S) and E>0 and E+S≤3 → (0,E+S)

37两瓶中油全倒入3两瓶

6

(E,S) and S>0 and E+S≤7 → (E+S,0)

3两瓶中油全倒入7两瓶

7

(E,S) and S<3 and E+S≥3 → (E+S-3,3)

用7两瓶油装满3两瓶子

8

(E,S) and E<7 and E+S≥7 → (7,E+S-7)

用3两瓶油装满7两瓶子

在每个状态(E,S)下,我们均可以通过判断E、S的值来选择上述若干条规则进行状态转变。整个状态空间构成了一颗树,树根是初始状态(R,S)=(0,0),目标状态(R,S)=(5,0)则可能位于某些节点中。

因为该问题的状态空间较小,最多不超过(7*3=21)种状态,因此在实验中我们采用深度搜索的方法对问题进行求解。此外,为了避免对已经搜索过的状态重复搜索,程序中定义了一个数组,用于存储已经搜索过的状态,仅有当当前状态没有在该数组中出现过时,算法才对其进行搜索,并将该状态放入数组中。

3.程序流程

4.核心伪代码

function isVisited(E, S): 状态(E, S)是否搜索过,没有则将其入栈并标记已搜索。

初始状态(E, S) = (0, 0),并存入栈Stack

while 栈Stack不为空:

取出栈顶元素(E, S),并输出

If (E, S) == (5, 0), then

分油成功,break;

if E < 7, then:

(E, S) = (7, S), isVisited(E, S)

if E < 3, then:

(E, S) = (E, 3), isVisited(E, S)

if E > 0, then:

(E, S) = (0, S), isVisited(E, S)

if S > 0, then:

(E, S) = (E, 0), isVisited(E, S)

if E > 0 and E+S <= 3, then:

(E, S) = (0, E+S), isVisited(E, S)

if S > 0 and E+S <= 7, then:

(E, S) = (E+S, 0), isVisited(E, S)

if S < 3 and E+S >= 3, then:

(E, S) = (7, S), isVisited(E+S-3, 3)

if E < 7 and E+S >= 7, then:

(E, S) = (7, S), isVisited(7, E+S-7)

end

5.代码运行及测试

算法运行结果如下所示,经过10次操作后,准确得将油划分为两个五两。

6.结论

本实验是对状态空间采用深搜的方法实现的。程序中设置了辅助数组用于保存已经搜索过的状态,且该问题的状态空间很小,因此深搜不会出现无穷解的情况。只要目标状态设置合理且存在,深搜一定能在有限的步骤里求得。但是在小孩分油问题中,深搜所得结果不一定为最优,广搜下得到的结果才是最优结果。但是由于深搜易于实现且速度快,因此实验中才选择深搜去实现。

本实验源码具有较强的扩展性,只要初始状态和目标状态设置合理,程序均可以成功将其状态转换过程输出。

7.源码

#include<iostream>
#include<stack>
#include<vector>
using namespace std;struct State {int E; // 七两的瓶子 int S; // 三两的瓶子 State(int E, int S) {this->E = E;this->S = S;}
};//  深搜辅助栈
stack<State> Stack;// 存储已经出现过的状态
vector<State> visited;// 查询状态s先前是否出现过
bool isVisited(State s) {vector<State>::iterator it;for (it = visited.begin(); it != visited.end(); it++) {if (it->E == s.E && it->S == s.S) return true;}return false;
}// 倒油行为,状态转变
void move(State s) {// 查询当前状态先前是否访问过if (!isVisited(s)) {visited.push_back(s);Stack.push(s);}
}int main() {int E = 0, S = 0;int fE = 5, fS = 0;cout<<"Please input the initial oil of bottles:"<<endl;cin>>E>>S;cout<<"Please input the final oil of bottles:"<<endl;cin>>fE>>fS;Stack.push(State(E, S));while(!Stack.empty()) {State cur = Stack.top(); Stack.pop();E = cur.E;S = cur.S;cout<<10 - E - S<<" "<<E<<" "<<S<<endl;// 到达目标状态 if (E == fE && S == fS) {cout<<"Successfully reach the target state:("<<fE<<", "<<fS<<")!";return 0;}// 将七两的瓶子装满if (E < 7) move(State(7, S));// 将三两的瓶子装满if (S < 3) move(State(E, 3));// 将七两的瓶子倒空if (E > 0) move(State(0, S));// 将三两的瓶子倒空if (S > 0) move(State(E, 0));// 将七两的瓶子全部装到三两的瓶子上if (E > 0 && E + S <= 3) move(State(0, E + S));// 将三两的瓶子全部装到七两的瓶子上if (S > 0 && E + S <= 7) move(State(E + S, 0));// 用七两的瓶子将三两的瓶子装满if (S < 3 && E + S >= 3) move(State(E + S - 3, 3));// 用三两的瓶子将七两的瓶子装满if (E < 7 && E + S >= 7) move(State(7, E + S - 7));}cout<<"Algorithm cannot find a solution!"<<endl;return 0;
}

转载于:https://www.cnblogs.com/CSLaker/p/9875349.html

【深搜】小孩分油问题相关推荐

  1. 深入递归、深搜dfs、回溯、剪纸学习。

    深入递归,深搜dfs,回溯,剪枝 参考于博客 一.双管齐下解递归 "逐步生成结果"类问题之数值型 自下而上的递归(递推,数学归纳,动态规划) 解决简单情况下的问题. 推广到稍复杂情 ...

  2. Go 分布式学习利器(15) -- Go 实现 深搜和广搜

    强化语法,回顾算法. 通过Go语言实现 深度优先搜索 和 广度优先搜索,来查找社交网络中的三度好友关系(三度指的是一个节点到 其相邻节点 到 其相邻节点的节点 ,图递增三层好友关系). 涉及到的Go语 ...

  3. 水管工游戏 (深搜)

    水管工游戏 本题依然是采用搜索,深搜,广搜都可以,本代码采用深搜,此题在搜索时需要增加一些判断条件以及下一步要搜索的位置即可. 代码如下: #include<stdio.h> int a[ ...

  4. Poj(2488),按照字典序深搜

    题目链接:http://poj.org/problem?id=2488 思路:按照一定的字典序深搜,当时我的想法是把所有的可行的路径都找出来,然后字典序排序. 后来,凡哥说可以在搜索路径的时候就按照字 ...

  5. [数据结构] 迷宫问题(栈和队列,深搜和广搜)

    代码: #include <iostream> #include <string.h> #include <stack> #include <queue> ...

  6. 迷宫问题最短捷径c语言深搜,迷宫问题 C语言实现(深搜)

    问题描述: 2015年05月21日 10:24:05 这是我自己出的一道题   其原型基于迷宫问题,用深搜来解决的!我就简单的说一说吧! 给定一个N * M 的迷宫!,1代表有障碍,0代表无障碍可通行 ...

  7. POJ-1724 深搜剪枝

    这道题目如果数据很小的话.我们通过这个dfs就可以完成深搜: void dfs(int s) {if (s==N){minLen=min(minLen,totalLen);return ;}for ( ...

  8. POJ2044 深搜+剪枝(云彩下雨)

    题意:        有一个城镇,是4*4的大小的,然后你控制一块云彩,2*2的,你每天可以有9种走的方法,上下左右,或者不动,走的时候可以走1或者2步,云彩所在的地方肯定会下雨,然后给你做多365天 ...

  9. hdu4876 深搜+(随机枚举剪枝)

    题意:       给你n个数,让你从选择k个数,然后排成一个环(k个数的顺序随意,但是排成一个环后就不能变了),然后可以在这个环上任意的找连续w个数(w<=k),可以找多次,得到一个值等于当前 ...

最新文章

  1. [python教程入门学习]python学习笔记(CMD执行文件并传入参数)
  2. tm1650中文资料_TM1616,TM1650,TM1651 SOP16原厂直销,技术支持
  3. ctime、mtime、atime
  4. 2021年5月信息系统项目管理师上午真题
  5. zookeeper基本原理及适用场景 转:http://blog.chinaunix.net/uid-26748613-id-4536290.html
  6. Mysql中SQL语句不使用索引的情况
  7. JavaSE04、什么是类和对象,如何使用?
  8. linux可配置哪些服务,不可不知 十大热门Linux服务器配置
  9. Linux 搭建SVN server
  10. sv_labs学习笔记——sv_lab4(System Verilog)
  11. mybatis的set标签
  12. Penn Treebank Tags做点小翻译 (下篇)
  13. Civil3D绘制路线
  14. 【Linux】系统移植篇四--uboot移植
  15. 通过小白三步装机版安装win10系统教程
  16. jpeg图片的exif信息
  17. 仓库盘点好方法,使用安卓盘点机PDA扫描商品条码进行超市盘点
  18. vga转HDMI与hdmi转VGA区别
  19. 2018年最流行的十大编程语言,有你用的吗?
  20. c语言程序女设计教学效果分析,提高C程序设计教学效果的策略

热门文章

  1. 阿里云机器学习平台PAI论文高效大模型训练框架Whale入选USENIX ATC‘22
  2. (Java毕业设计)旧车交易撮合管理平台(java+mysql+b/s架构)附源码
  3. 微信投票系统源码--微信投票系统开发功能介绍以及源码分享
  4. Java 判断实体类对象的全部属性是否空
  5. 写给大忙人看的 - Java中图片压缩上传至MinIO服务器(4)
  6. HCIP(三)---点到点网络类型
  7. 【时空序列预测paper】ConvLSTM:A Machine Learning Approach for Precipitation Nowcasting
  8. 第R1周:RNN-心脏病预测
  9. MySQL递归查询上下级菜单
  10. 美国能限制linux内核,因故意引入漏洞,美国一所大学被禁止为 Linux 内核做贡献...