题目描述:

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.

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 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

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.
You may assume that the input you are given does have a solution.

输入:

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.

输出:

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.

样例输入:

3 7 1
9 32 6

样例输出:

fill B
pour B A
empty A
pour B A
success
fill B
pour B A
empty A
pour B A
empty A
pour B A
empty A
pour B A
fill B
pour B A
empty A
pour B A
empty A
pour B A
empty A
pour B A
empty A
pour B A
fill B
pour B A
empty A
pour B A
empty A
pour B A
success

提示:

倒水问题的经典形式是这样的:

“假设有一个池塘,里面有无穷多的水。现有2个空水壶,容积分别为5升和6升。问题是如何只用这2个水壶从池塘里取得3升的水。”

当然题外是有一些合理的限制的,比如从池塘里灌水的时候,不管壶里是不是已经有水了,壶一定要灌满,不能和另一个壶里的水位比照一下“毛估估”(我们可以假设壶是不透明的,而且形状也不同);同样的,如果要把水从壶里倒进池塘里,一定要都倒光;如果要把水从一个壶里倒进另一个壶里,也要都倒光,除非在倒的过程中另一个壶已经满了;倒水的时候水没有损失(蒸发溢出什么的)等等等等。

事实上,要解决上面这题,你只要用两个壶中的其中一个从池塘里灌水,不断地倒到另一个壶里,当第二个壶满了的时候,把其中的水倒回池塘里,反复几次,就得到答案了。以5升壶(A)灌6升壶(B)为例:

A  B
0  0
5  0  A→B
0  5
5  5  A→B
4  6
4  0  A→B
0  4
5  4  A→B
3  6

现在我们问,如果是多于2只壶的情况怎么办(这样一来就不能用上面的循环倒水法了)?如何在倒水之前就知道靠这些壶是一定能(或一定不能)倒出若干升水来的?试举数例:
1) 两个壶:65升和78升,倒38升和39升。
2) 三个壶:6升,10升和45升,倒31升。

我们可以看到,在1)中,65=5×13,78=6×13,而39=3×13。所以如果把13升水看作一个单位的话(原题中的“升”是没有什么重要意义的,你可以把它换成任何容积单位,毫升,加仑——或者“13升”),这题和最初的题目是一样的。而38升呢?显然是不可能的,它不是13的倍数,而65升和78升的壶怎么也只能倒出13升的倍数来。也可以这样理解:这相当于在原题中要求用5升和6升的壶倒出38/39升来。

那么2)呢?你会发现,只用任何其中两个壶是倒不出31升水的,理由就是上面所说的,(6,10)=2,(6,45)=3,(10,45)=5,(这里(a,b)是a和b的最大公约数),而2,3,5均不整除31。可是用三个壶就可以倒出31升:用10升壶四次,6升壶一次灌45升壶,得到1升水,然后灌满10升壶三次得30升水,加起来为31升。

一般地我们有“灌水定理”:

“如果有n个壶容积分别为A1,A2,……,An(Ai均为大于0的整数)设w为另一大于0的整数。则用此n个壶可倒出w升水的充要条件为:
1) w小于等于A1+A2+…+An;
2) w可被(A1,A2,…,An)(这n个数的最大公约数)整除。”

这两个条件都显然是必要条件,如果1)不被满足的话,你连放这么多水的地方都没有。2)的道理和上面两个壶的情况完全一样,因为在任何步骤中,任何壶中永远只有(A1,A2,…,An)的倍数的水。

现在我们来看一下充分性。在中学里我们学过,如果两个整数a和b互素的话,那么存在两个整数u和v,使得ua+vb=1。证明的方法很简单:在对a和b做欧几里德辗转相除时,所有中间的结果,包括最后得到的结果显然都有ua+vb的形式(比如第一步,假设a小于b,记a除b的结果为s,余数为t,即b=sa+t,则t=(-s)a+b,即u=-s,v=1)。而两个数互素意味着欧几里德辗转相除法的最后一步的结果是1,所以1也可以记作ua+vb的形式。稍微推广一点,如果(a,b)=c,那么存在u和v使得ua+vb=c(两边都除以c就回到原来的命题)。

再推广一点,如果A1,A2,……,An是n个整数,(A1,A2,…,An)=s,那么存在整数U1,U2,……,Un,使得

U1A1 + U2A2 + … + UnAn = s.    (*)

在代数学上称此结果为“整数环是主理想环”。这也不难证,只要看到

(A1,A2,A3,A4,…,An) = ((((A1,A2),A3),A4),…,An).

也就是说,可以反复应用上一段中的公式:比如三个数a,b,c,它们的最大公约数是d。假设(a,b)=e,那么(e,c)=((a,b),c)=d。现在有u1,u2使得u1a+u2b=e,又有v1,v2使得v1e+v2c=d,那么

(v1u1)a+(v1u2)b+(v2)c=d.

好,让我们回头看“灌水定理”。w是(A1,A2,…,An)的倍数,根据上节的公式(*),两边乘以这个倍数,我们就有整数V1,V2,……,Vn使得 V1A1 + V2A2 + … + VnAn = w.注意到Vi是有正有负的。

这就说明,只要分别把A1,A2,……,An壶,灌上V1,V2,……,Vn次(如果Vi是负的话,“灌上Vi次”要理解成“倒空-Vi次”),就可以得到w升水了。具体操作上,先求出各Vi,然后先往Vi是正数的壶里灌水,灌1次就把Vi减1。再把这些水到进Vi是负数的壶里,等某个壶灌满了,就把它倒空,然后给这个负的Vi加1,壶之间倒来倒去不变更各Vi的值。要注意的是要从池塘里灌水,一定要用空壶灌,要倒进池塘里的水,一定要是整壶的。这样一直到所有Vi都是0为止。

会不会发生卡住了,既不能灌水又不能倒掉的情况?不会的。如果有Vi仍旧是负数,而Ai壶却没满:那么如果有其它Vi是正的壶里有水的话,就都倒给它;如果有其它Vi是正的壶里没水,那么就拿那个壶打水来灌(别忘了给打水的壶的Vi减1);如果根本没有任何Vi是正的壶了——这是不可能的,这意味着w是负的。有Vi仍旧是正数,而Ai壶却没满的情况和这类似,你会发现你要用到定理中的条件1)。

这样“灌水定理”彻底得证。当然,实际解题当中如果壶的数目和容积都比较大的话,手工来找()中的各Ui比较困难,不过可以写个程序,连倒水的步骤都算出来。最后要指出的一点是,()中的Ui不是唯一的,所以倒水的方式也不是唯一的。

实现代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<vector>
#include<queue>
using namespace std;const int maxn = 1e5+10;
const int smaxn = 1010;
int table[smaxn][smaxn];
int front=0, last=0;
char strs[7][20]={"", "fill A\n", "fill B\n", "empty A\n", "empty B\n", "pour A B\n", "pour B A\n"};struct node{int a, b;int op;int pre; //上一个状态
}tree[maxn];    //用数组的,线性存储结构来构造队列。node manipulate(node now, int way, int ca, int cb){int a = now.a;int b = now.b;node next;switch(way){case 1: a=ca; break;  //fill A case 2: b=cb; break;  //fill Bcase 3: a=0; break;    //empty A case 4: b=0; break;  //empty Bcase 5:if(a+b-cb>=0) {a=a+b-cb; b=cb;} //pour A B 判断溢出else {b=a+b; a=0;} break;case 6: if(a+b-ca>=0) {b=a+b-ca; a=ca;} //pour B A 判断溢出else {a=a+b; b=0;} break;}next.a = a;next.b = b;next.op = way;return next;
}int BFS(int ca, int cb, int n){//初始化node ans[100];memset(table, 0, sizeof(table));front=last=0;node S={0};//在tree的基础上,添加两个指针,实现队列的操作。采用线性存储结构来构造队列。//last指向队尾,front指向队首;//S入队列tree[last++] = S;//当队列为空时中断循环,即队首指针与队尾指针 重合。while(front != last){node now = tree[front];if(now.b == n) {return front;}table[now.a][now.b] =1; //标记当前状态 为 访问过,入队过。//对当前状态 执行6种操作,得到6个下一状态。for(int i=1; i<=6; i++){node next = manipulate(now, i, ca, cb);next.pre = front;if(table[next.a][next.b] == 0){tree[last++] = next;table[next.a][next.b] = 1; //标记当前状态 为 访问过。}//当前状态,如果不曾访问,曾入队列 待阅兵。反之跳过。if(next.b==n){break;}} //队首出列类比于pop(),以便得到队列的下一队首。front++;}return -1;
}void print(int index){if(index == -1) {//printf("FAIL\n"); return;}stack<int> st;//遍历操作序列,并入栈while(index != 0){st.push(tree[index].op);index = tree[index].pre;}while(!st.empty()){printf("%s", strs[st.top()]); st.pop();}printf("success\n");
}int main(){int ca, cb, n;while(scanf("%d%d%d", &ca, &cb, &n)!=EOF){print(BFS(ca, cb, n));}return 0;
}

Codeup100000609问题 A: Jugs相关推荐

  1. UVA571 - Jugs(数论)

    UVA571 - Jugs(数论) 题目链接 题目大意:给你A和B的水杯.给你三种操作:fill X:把X杯里面加满水.empty X:把X杯中的水清空.pour X Y 把X的水倒入Y中直到一方满或 ...

  2. 问题 A: Jugs

    时间限制: 1 Sec  内存限制: 32 MB 提交: 288  解决: 0 [提交][状态][讨论版][命题人:外部导入] 题目描述 In the movie "Die Hard 3&q ...

  3. c语言大小写字母互换1005,1005 Jugs,1005jugs

    1005 Jugs,1005jugs 辗转相减,新手入门题.两个容量的灌水题,无所谓最优解. 1 #include 2 3 intmain(){4 intA,B,T,sA,sB;5 while(sca ...

  4. ZOJ Problem 1005 jugs

    题目 In the movie "Die Hard 3", Bruce Willis and Samuel L. Jackson were confronted with the ...

  5. 扩展欧几里德算法解决问题A:Jugs

    Jugs codeup的Jugs题目需要使用扩展欧几里德算法解决: Zoj的jugs题目需要使用BFS算法解决: codeup的Jugs题目需要使用扩展欧几里德算法解决: 题目链接:http://co ...

  6. zoj 1005 Jugs BFS

    感想:这是我的第一道oj题,思路我想了很久,感觉建模能力还是不够强啊,理清楚了就好,把各个操作看成一条路,BFS就好 http://acm.zju.edu.cn/onlinejudge/showPro ...

  7. uva 571 Jugs

    原题: In the movie "Die Hard 3", Bruce Willis and Samuel L. Jackson were confronted with the ...

  8. poj1066 Jugs

    poj1066 Jugs http://poj.org/problem?id=1606 解题思路:本题可以用数学方法解得,最易理解,常规的解法是搜索.直接用接近模拟的广度优先搜索即可过. 给两个容器, ...

  9. KY261 Jugs

    KY261 Jugs 题目地址 相对素数:不能被所有给定的整数(除了0)整除的数 题目描述: In the movie "Die Hard 3", Bruce Willis and ...

最新文章

  1. 数据分析IJCAI 2020:录用率12.6%,华人占据半壁江山,表征学习、GNN成热点 | AI日报...
  2. 10 Windows编程——鼠标消息
  3. 多媒体技术 PI 第二期:OSS 圆桌预告
  4. 身份反模式:联邦筒仓和意大利面条身份
  5. igmp是哪个层协议_通俗易懂网络协议(IP)
  6. 表面招助理实为“拉皮条”?招聘平台也有情色陷阱,BOSS直聘回应...
  7. 掌握 Ajax,第 1 部分: Ajax 入门简介
  8. 在线文本按列截取工具
  9. Java实现贪吃蛇大作战小游戏(完整版)
  10. Unity制作3d生存游戏视频教程
  11. 为什么csgo一直显示连接官方服务器失败,CSGO提示连接任意官方服务器失败怎么办?五大详细解决方法看这里!...
  12. 你知道strong和b;i和em的区别吗?
  13. 基于SpringBoot+Bootstrap【爱码个人博客系统】附源码
  14. Makefile中wildcard使用方法
  15. 计算机考研数学考数学二的专业,考研常识:哪些专业考数学二?
  16. 靖江最正宗过年习俗 只有3%的人完全继承下来了
  17. 速卖帮AI点餐流程 AI菜品识别结账
  18. python空间点赞_用Python登录好友QQ空间点赞
  19. 微信开发者工具source看不了代码_微信开发者工具和开发
  20. 机器视觉引导定位系统,工业视觉定位检测

热门文章

  1. 旷世科技IoU-Net
  2. nomachine NX 远程连接相关问题
  3. 数据仓库指北(文末附PDF下载)
  4. vue3 实现监听store里state状态变化
  5. 2020大疆校招B卷第二题
  6. 示波器学习(一):示波器的作用、类型和基本结构
  7. Eclipse 各种设置
  8. matlab用方程的解赋值,Matlab隐式符号方程求解和赋值
  9. I have a dream
  10. Windows 2008 R2 x64 Enterprise安装postgres (api-ms-win-crt-runtime-l1-1-0.dll、 0x80240017错误)