算法谜题——三个水壶问题
问题:有一个充满水的8品脱的水壶和两个空水壶(容积分别是5品脱和3品脱)。通过将水壶完全倒满水和将水壶的水完全倒空这两种方式,在其中的一个水壶中得到4品脱的水。
解法:可以把每次三个水壶中水的量组成一个状态,比如初始状态为008,对应第一个水壶0品脱水,第二个水壶0品脱水,第三个水壶8品脱水。对题目的状态空间图进行广度优先遍历。当表示状态的数字中出现4时,即求出答案。
1、为了打印出倒水的过程,需要声明一个前置状态保存当前状态由哪个状态转换而来,然后就可以回溯到初始状态,打印出倒水过程。相当于树中的父结点。
2、可以声明一个map表,保存已有的状态,对已有的状态,就不再向下继续遍历,这样可以节省求解时间。
3、因为是广度优先遍历,所以第一次解得的答案所需的倒水的次数最少,解为最优解。
#include <iostream>
#include <vector>
#include <map>
#define MaxFirst 3
#define MaxSecond 5
#define MaxThird 8
using namespace std;class State
{
public:int second;int num[3];State* preState;static map<int,int> mapping;public:State(int first,int second,int third){num[0]=first;num[1]=second;num[2]=third; }void init(){ mapping[0]=MaxFirst;mapping[1]=MaxSecond;mapping[2]=MaxThird;}bool canPour(int from,int to)//判断是否可以从from水壶中倒水到to水壶中{if(num[from]==0){return false;}if(num[to]==mapping[to]){return false;}else {return true;}}void pour(int from,int to)//倒水过程{if(num[from]+num[to]>mapping[to]){num[from]=num[from]-(mapping[to]-num[to]);num[to]=mapping[to];}else{num[to]=num[to]+num[from];num[from]=0;}}};
map<int,int> State::mapping;int main()
{map<int,int> states;State *start=new State(0,0,8);start->init();State *state=start;State *endState=new State(8,8,8);//只有获得解endState才会改变,赋值全为8为了方便判断是否获得最终解vector<State> action;//保存所有状态对象action.push_back(*start);//把初始状态先加入队列中int n=0;do{for(int i=0;i<3;i++)//双层循环为从i水壶中倒水入j水壶中{for(int j=0;j<3;j++){if(i!=j){if(state->canPour(i,j)){state->pour(i,j);if(states[state->num[0]*100+state->num[1]*10+state->num[2]]==0)//如果该状态不在hash表中,即为第一次出现该状态{states[state->num[0]*100+state->num[1]*10+state->num[2]]++;(state->preState)=new State(action[n]);action.push_back(*state);if(state->num[0]==4||state->num[1]==4||state->num[2]==4)//获得解{endState=state;i=4;break; }}}}*state=action[n];} }n++;}while(endState->num[0]==8&&endState->num[1]==8&& n<action.size());cout<<endState->num[0]<<" "<<endState->num[1]<<" "<<endState->num[2]<<endl;state=endState;do{state=state->preState;cout<<state->num[0]<<" "<<state->num[1]<<" "<<state->num[2]<<endl; }while(state->num[2]!=8);return 0;
}
运行结果如图,从下往上即为倒水的过程
如果需要倒出水壶含7品脱的情况,把
if(state->num[0]==4||state->num[1]==4||state->num[2]==4)
中的4改成7,运行出结果如下:
算法谜题——三个水壶问题相关推荐
- 《算法谜题》-第二章 谜题
1.狼羊菜过河 2.手套选择 3.矩形切割 4.士兵摆渡 5.行列变换 6.数数的手指 7.夜过吊桥 8.拼图问题 9.心算求和 10.硬币中的假币 11.假币堆问题 12.平铺多米诺问题 13.被堵 ...
- c语言勾股定理程序流程图,方法总结1.表达算法的方法有自然语言.流程图和基本算法语句三种.先有自然语言.再画流程图.最后才能写出基本算法语句.即程序,——青夏教育精英家教网——...
考点一:自然语言表示的算法 [内容解读]通过对解决具体问题过程与步骤的分析,体会算法的思想,了解算法的含义:对于某一问题往往可以设计出多种算法,通过选用步骤最少的.结构最好的算法. [命题规律]以选择 ...
- K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means)介绍与对比
原文:http://www.cnblogs.com/yixuan-xu/p/6272208.html K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means ...
- 用python解算法谜题_编程的乐趣 用Python解算法谜题
这是一本介绍通过解决复杂谜题来学习编程的书,书中的代码用Python语言编写.与以往的编程书不同,本书将对代码功能的理解与编程语言语法和语义的理解分离开来,从解每个谜题开始,先给出解谜题的算法,随后用 ...
- leetcode旋转数组 c语言,leetcode explore 初级算法第三题,旋转数组代码实现
leetcode explore 初级算法第三题,旋转数组代码实现.原题链接: 题目分析 因为题目不是很长,这里把题目贴出来: 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. ...
- 理解GBDT算法(三)——基于梯度的版本
理解GBDT算法(三)--基于梯度的版本 标签: GBDT梯度残差代价函数回归树 2015-03-31 16:13 1395人阅读 评论(3) 收藏 举报 本文章已收录于: 分类: Machin ...
- 有向图最长路径算法_算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法...
强连通分量分解的Kosaraju算法 今天是算法数据结构专题的第35篇文章,我们来聊聊图论当中的强连通分量分解的Tarjan算法. Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起 ...
- js实现阶乘算法的三种方法
js实现阶乘算法的三种方法 // 非递归写法 function f(n) {if (0 === n) {return 1;}let res = 1;for (let i = 1; i <= n; ...
- A*算法(三)算法实现
A*算法(三)算法实现 1. Array2D类 2. Point类 3. AStar类 3.1 Node类 3.2 初始化处理 3.3 判断函数 3.4 搜索结点周围的点 3.5 寻路 4. 地图显示 ...
最新文章
- 工作中常用的第三放的框架
- Centos7安装Python3并更改默认版本为python3(编译安装)
- 如何用计算机打出love,游戏中名字的LOVE怎么用符号打出来?
- MyBatis开发步骤
- CODEVS——T 1049 棋盘染色
- HTML 文档流和文本流的理解
- git eclipse 取消误操作 ignore(忽略)文件
- c语言if语句判断ab大小,C语言条件语句ifppt课件
- Spring Boot 项目集成Windows域账户认证
- MFC调用RDP实现远程桌面共享实例
- 平面图最小割 BZOJ 2006
- S4 HANA CO和FI自动集成:成本中心分配分摊业务实践-KSV5/KSU5
- 【翻译】WhatsApp 加密概述(技术白皮书)
- 新媒体运营 | 6个自动写文案的宝藏网站,助你摆脱灵感枯竭
- office2007的Excel当中如何打开两个独立窗口
- 【算法Algorithm】计数(Count)排序
- cocos creator中FBX文件不可用显示asset invalid
- Flink 计算 TopN
- 基础SQL Server 操作问题——仅当使用了列表并且IDENTITY_INSERT为ON时,才能为表中的标识列制定显示值
- COINDAO将迎来首次回购分红,COINDAO白名单和团队长参与方式。