典型例子

两个水桶分别可以装3L水和5L水,没有刻度,请问怎么装出4L的水。
解答
设A为小桶,B为大桶。
则过程中的每个状态可以如下表示:
方法一:
A B
0 5
3 2
0 2
2 0
2 5
3 4
此时B中装了4L水,共计6步

方法二:
A B
3 0
0 3
3 3
1 5
1 0
0 1
3 1
0 4
此时B中装了4L水,共计8步。

现然方法一比方法二可以更快得到结果。这两者的区别其实就在于:
方法一 是刚开始的时候,大桶装满,倒到小桶里面,方法二是小桶装满倒入大桶里面。也就是一个正逆序的问题。

思路

通过上面的例子,我们可以了解到这看似是两个方案。但是却只是一个正序和一个逆序罢了。
那么我们可以求出一个通解吗?
下面我们再来看上面那个例子。
按照固定的思路
1.假设A桶小,B桶大,且小桶可装m升水,大桶可装M升水。
2.我们一般情况下,肯定是把水装到大桶里面去。例如4L的水,肯定不能装到3L的桶里面去,必须装入5L的桶里面去。因此我们可以考虑,先把小桶装满,往大桶里面倒。
开始倒:
最初A和B中装的水都是0L,这是两个空桶。

0 0
A B
3 0 //A先装满(A=A+3)
0 3 //A中的水倒入B中(B=B+A,B小于5,则A=0;B大于等于5,则A=B-5)
3 3 //A装满(A=A+3)
1 5 //此时重复第二行
1 0 //将B中的水倒出(将B置零)
0 1 //A倒入B中(A和B互换)
3 1 //重复第二行
0 4
3 4 //此时B中已经有4L的水了。这上面便是方法二。此时不要停止,继续倒水
2 5
2 0 //重复第二行
0 2
3 2
0 5
//从最开始A=3.B=0,到了现在变成了A=0,B=5;完成了一个轮回。

我们如果把下面的这个粗体数字逆序来看看,发现这正是方法一
这里的3就是小桶容积m,5就是大桶容积M。
这是偶然的吗?
我们继续验证一下。

例子2:有一个2L的桶和6L的桶,如何装出4L的水?
此时m=2;M=6;
按照我们之前的思路:
A B
2 0 //A=A+m
0 2 //B=B+A,B小于M,则A=0;B大于等于M,则A=B-M
2 2
0 4 //此时已经得出4L的水了。不要停止,继续倒水。
2 4
0 6
//结束。

通过上面两个例子,我们发现了其算法的思路:
本质上都是在不断重复第二行的算法。
通过上面的例子,我们可以清晰的看到,正序和逆序的算法步骤的数量是不相等的,而我们肯定是想要次数最少的步骤,于是可以把上下两部分的步骤次数进行一次对比,然后输出次数最少的一种
注意:这里并不是说明,逆序就是最短的,这里跟用要求称出的的水的体积有关。
注意2:如果我们经过了一个轮回,但是在大桶的轨迹中并没有找到需要的刻度,则可以认为该刻度不可达,则认为是无解的。

代码实现:

#include"iostream"
#include"algorithm"
#include"vector"
using namespace std;void output(vector<int> a,vector<int> b,int L)//输出函数,用来输出结果
{vector<int>::iterator ita, itb ,it;for (it = b.begin(); it < b.end(); it++)//在大桶的轨迹b中搜寻指定的刻度{if (*it == L)break;}if(it==b.end())//如果搜寻到b的末尾还没有找到对应刻度,则说明无解{cout << "No Solution" << endl;return;}cout << "A" << "\t" << "B" << endl;if (b.end() - it - 1 > it - b.begin() + 1)//判断是后半部分长还是前半部分更长。{  ita = a.begin();itb = b.begin();while (itb <= it){cout << *ita << "\t" << *itb << endl;ita++; itb++;}}else{for (it = b.end()-1; it > b.begin(); it--){if (*it == L)break;}ita = a.end()-1;itb = b.end()-1;while (itb >= it){cout << *ita << "\t" << *itb << endl;ita--; itb--;}}cout << "B中装了" << L << "升水" << endl;
}void Bucket_problem()
{int A, B, L;vector<int> A1, B1;//用两个向量保存两条数据,到时候容易比较长短和输出int flag = 0;cout << "请输入两个容器的体积(正整数):" << endl;cin >> A >> B;cout << "请输入想要装出的水的体积(正整数):" << endl;cin >> L;cout << "此时A为小桶,B为大桶" << endl;int M = max(A, B);int m = min(A, B);if (L > M){cout << "No Solution" << endl;return ;}if (L == m){cout << "A" << "\t" << "B" << endl;cout << m << "\t" << "0" << endl;cout << "此时A中装了" << m << "升水" << endl;return ;}if (L == M){cout << "A" << "\t" << "B" << endl;cout << "0" << "\t" << M << endl;cout << "此时B中装了" << M << "升水" << endl;return ;}int a = 0, b = 0;a = m;while (true)//制造一个循环{if (b == M){b = 0;if (a == 0 && b == 0) break;//退出条件A1.push_back(a); B1.push_back(b);swap(a, b);A1.push_back(a); B1.push_back(b);a = m;continue;}A1.push_back(a); B1.push_back(b);//       cout << A << "\t" << B;b = b + a;if (b >= M){a = b - M;b = M;A1.push_back(a); B1.push_back(b);}else{a = 0;A1.push_back(a); B1.push_back(b);a = m;}}output(A1, B1, L);
}
int main()
{Bucket_problem();system("pause");return 0;
}

结束语

其实这个问题并不难。通过对于例子的观察,自己的判断,很容易发现规律,总结规律并用代码实现就可以了。切忌空想不动手。

【C++】给定两个没有刻度的容器,对于任意给定的容积,求出如何只用两个瓶装出L升的水相关推荐

  1. 倒水问题:给定两个没有刻度的容器,对于任意给定的容积,求出如何只用两个瓶装出L升的水,如果可以,输出步骤,如果不可以,输出no solution

    倒水问题:给定两个没有刻度的容器,对于任意给定的容积,求出如何只用两个瓶装出L升的水,如果可以,输出步骤,如果不可以,输出no solution 这个问题我找了百度,发现没有比较好的代码,有一些只判断 ...

  2. 算法----- 给定一颗二叉树,找到二叉树上任意两个节点之间的距离(Java版本)

    题目: 给定一颗二叉树,找到二叉树上任意两个节点之间的距离 class TreeNode {TreeNode left;TreeNode right;} 思路: 首先找到一个节点的路径,然后找到另一个 ...

  3. 编程笔试(解析及代码实现):求不重复数字之和​​​​​​​给定一组整型数字,里面有且仅有两个数字值出现了一次,其他的数字都出现了两次。请写出程序求出这两个只出现了一次的数字之和

    编程笔试(解析及代码实现):求不重复数字之和给定一组整型数字,里面有且仅有两个数字值出现了一次,其他的数字都出现了两次.请写出程序求出这两个只出现了一次的数字之和 目录 题目描述 代码实现 题目描述 ...

  4. 给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。

    描述 给一个整数数组,找到两个数使得他们的和等于一个给定的数 target. 你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标.注意这里下标的范围是 0 到 n-1. ...

  5. 效用分析 ( 效能分析、Power analysis)是什么?效用分析在线计算器介绍(分析样本量、效用和效应量之间的关系时,需要把其中一个因素固定,计算另外两个因素间的关系、或者给定两个因素计算第三个

    效用分析 ( 效能分析.Power analysis)是什么?效用分析在线计算器介绍(分析样本量.效用和效应量之间的关系时,需要把其中一个因素固定,计算另外两个因素间的关系.或者给定两个因素计算第三个 ...

  6. (C/C++)给定两个长度为m和n的有序列表,以O(logm+logn)复杂度找出有序列表第k小的数

    给定两个长度为m和n的有序列表,以O(logm+logn)复杂度找出有序列表第k小的数 思路 logm+logn即可推断是分治,每次折半得到两个数组的A[midA]和B[midB],有: A[midA ...

  7. 微策略2011校园招聘笔试题(找出数组中两个只出现一次的数字)

    1.8*8的棋盘上面放着64个不同价值的礼物,每个小的棋盘上面放置一个礼物(礼物的价值大于0),一个人初始位置在棋盘的左上角,每次他只能向下或向右移动一步,并拿走对应棋盘上的礼物,结束位置在棋盘的右下 ...

  8. 找出不是两个数组共有的元素

    题目 练习7-4 找出不是两个数组共有的元素 (20 分) 给定两个整型数组,本题要求找出不是两者共有的元素. 输入格式: 输入分别在两行中给出两个整型数组,每行先给出正整数N(≤20),随后是N个整 ...

  9. 找出数组中两数之和为指定值的所有整数对

    一,问题描述 给定一个整型数组(数组中的元素可重复),以及一个指定的值.打印出数组中两数之和为指定值的 所有整数对 二,算法分析 一共有两种方法来求解.方法一借助排序,方法二采用HashSet 方法一 ...

  10. 任意给定一个正整数N,求一个最小的正整数M(M1),使得N*M的十进制表示形式里只含有1和0。...

    题目:任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0. 解法一:暴力求解.从1开始查找M,然后判断M*N=X这个数字是否只含有0,1. 解法二:由 ...

最新文章

  1. mysql查询赋值、修改拼接字符串
  2. phone clone android,Phone Clone
  3. appium 3 跑起来
  4. rodbc 连接oracle,在R中加密密码 – 使用RODBC连接到Oracle DB
  5. php怎么生成卡券签名,小程序卡券签名错误的解决方案
  6. mysql declare 赋值_sql server和mysql变量赋值的区别 以及 MySql Declare
  7. 雷军被重新任命为金山软件董事会副主席
  8. 科室鄙视链最低端,居然是这类人
  9. leetcode —— 面试题 16.19. 水域大小
  10. python往list中添加tuple
  11. 当程序员写不出代码了,该怎么办?
  12. C语言家谱管理程序,C语言实现家谱管理
  13. 给GridView编辑列按钮添加客户端提示信息
  14. ubuntu-查看所有用户
  15. POWER BI | 注册
  16. 01-什么是网络爬虫
  17. 电驴搜索服务器正在连接,电驴 电驴连接不上服务器-完美教程资讯
  18. could not resolve xxx.jar
  19. mp3处理工具(mp3agic)
  20. 音频采集 via Media Foundation

热门文章

  1. LTE FDD 时频资源
  2. android logo在线生成工具,在线生成logo
  3. 凯利讯分享ECL电路与TTL电路的使用注意事项
  4. elasticsearch学习一:了解 ES,版本之间的对应。安装elasticsearch,kibana,head插件、elasticsearch-ik分词器。
  5. 桔梗载药上浮 柴胡升于左 升麻生于右
  6. 机器学习笔记 - 什么是先验算法(Apriori Algorithm)?
  7. 工业互联网的内涵及其应用
  8. python录制音频
  9. 计算机考研专业课资料百度云,考研专业课资料(一)
  10. 微信昵称 mysql_MySQL数据库之解决微信昵称含特殊表情或字符无法存入数据库的异常问题...