Time limit: 3.000 seconds
限时:3.000秒
Background
背景
In the movie "Die Hard 3", Bruce Willis and Samuel L. Jackson were confronted with the following puzzle. They were given a 3-gallon jug and a 5-gallon jug and were asked to fill the 5-gallon jug with exactly 4 gallons. This problem generalizes that puzzle.
在电影《龙胆虎危》中,布鲁斯·威利斯和撒缪尔·杰克逊面临着一个难题。他们得到了两个分别为3加伦和5加伦的罐子,并要求在5加伦的罐子中准确的装入4加伦。本问题由此而生。
You have two jugs, A and B, and an infinite supply of water. There are three types of actions that you can use: (1) you can fill a jug, (2) you can empty a jug, and (3) you can pour from one jug to the other. Pouring from one jug to the other stops when the first jug is empty or the second jug is full, whichever comes first. For example, if A has 5 gallons and B has 6 gallons and a capacity of 8, then pouring from A to B leaves B full and 3 gallons in A.
现在给你两个罐子A和B,还有无限量的水。你只能干三件事:(1)装满罐子,(2)倒空罐子,(3)将一个罐子中的水倒入另一个罐子。两个罐之间倒水时,要在倒出的那只罐子被倒空,或是被倒入的那只罐子装满时为止。比方说,如果A中装有5加伦的水,B容量为8加伦,装有6加伦的水。当从A倒向B后,A中还剩3加伦。
A problem is given by a triple (Ca, Cb, N), where Ca and Cb are the capacities of the jugs A and B, respectively, and N is the goal. A solution is a sequence of steps that leaves exactly N gallons in jug B. The possible steps are
这个问题就是给定一个三元组(Ca, Cb, N),其中Ca和Cb分别是两个罐子A和B的的容量,N是目标水量。解法就是一系列的步骤,使得最后在B罐中得到N加伦的水。允许的步骤如下:
- fill A
- fill B
- empty A
- empty B
- pour A B
- pour B A
- success
where "pour A B" means "pour the contents of jug A into jug B", and "success" means that the goal has been accomplished.
其中“pour A B”表示将A罐中的水倒入B罐。“success”表示目标已经达到。
You may assume that the input you are given does have a solution.
你可以认为所有给定的输入都有解。
Input
输入
Input to your program consists of a series of input lines each defining one puzzle. Input for each puzzle is a single line of three positive integers: Ca, Cb, and N. Ca and Cb are the capacities of jugs A and B, and N is the goal. You can assume 0 < Ca ≤ Cb and N ≤ Cb ≤ 1000 and that A and B are relatively prime to one another.
输入到程序的数据由很多行构成,每行数据行定义一个题目。每行题目包括3个整数值:Ca、Cb和N。Ca和Cb分别是A罐与B罐的容量,N是目标水量。你可以认为0 < Ca ≤ Cb且N ≤ Cb ≤ 1000,A和B互质。
Output
输出
Output from your program will consist of a series of instructions from the list of the potential output lines which will result in either of the jugs containing exactly N gallons of water. The last line of output for each puzzle should be the line "success". Output lines start in column 1 and there should be no empty lines nor any trailing spaces.
你的程序应输入一组在上文中定义的步骤指令,使得无论哪个罐子最后准确的装入N加伦的水。输出的最行一行应该为“success”。输出从第一列开始,前面不能有空后,行尾不能有空格。
Sample Input
输入示例
3 5 4
5 7 3
Sample Output
输出示例
fill B
pour B A
empty A
pour B A
fill B
pour B A
success
fill A
pour A B
fill A
pour A B
empty B
pour A B
success
Analysis
分析
本题只要求给出一个解,不要求最优。所给的两个罐子容量一定互质,因此必然可以倒出从0到大罐容量间的任何整数值。原理是若A,B互质,则最小公倍数为A×B,即不存在一个1 < n < B,使得nA能被B整除。令r = nA mod B(mod为取模操作),那么当n从0到B-1变化时,r可以取到0到B-1之间的任何值。这个是很容易证明的,但我的证明过程非常不专业,还请各位数学老师给予指教!
现在的问题就是用AB两个罐子相互倒水来模拟这个数学过程。设小罐容量为A,大罐容量为B。每次将A装满后倒入B中。若第m次后B已装满,A剩下的水量为r1,则有:
- r1 = mA mod B
然后将B倒空,把A中剩余的r1装入B。又经过n次从把A装满倒入B的操作后B被装满,此时A剩下的水量为r2,则有:
- r2 = (r1 + nA) mod B
- = (mA mod B + nA) mod B
- = (m+n)A mod B
由此可知,倒的方法就是每次将A中的水倒进B,但每次在做这一步之间要先检查A、B中的水量,如果A为空,就将A装满;如果B已倒满,就将B清空。最后一定可以在某个时候在B罐中得到需要的水量。
Solution
解答
#include <iostream> #include <vector> using namespace std; int main(void) { //循环处理输入的每行数据 for (int nACap, nBCap, nDest; cin >> nACap >> nBCap >> nDest; ) { //开始循环从A到入B的算法,每次输出动作 for (int nA = 0, nB = 0; nB != nDest; cout << "pour A B\n") { //如果A罐已空,则装满A罐,并输出动作 if (nA == 0) { nA = nACap; cout << "fill A\n"; } //如果B罐已满,则倒空B罐,并输出动作 if(nB == nBCap) { nB = 0; cout << "empty B\n"; } //将A罐全部倒入B罐 nB += nA; nA = 0; //若发现B罐超量,则将超过部分倒回A罐 if (nB > nBCap) { nA = nB - nBCap; nB = nBCap; } } cout << "success" << endl; } return 0; }