ZOJ 1005 Jugs(BFS)

Jugs

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

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

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.

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
题意:有两个容量互质的容器,需要用这两个容器量出目标重量的水,找到其中一组解。
分析:对于每一个状态有六种操作方法:倒满A,倒满B,清空A,清空B,从A倒到B,从B倒到A。可采用广度优先搜索,使得搜索到的解为步数最少的解。
  1 //Problem Name: Jugs
  2 //Source: ZOJ 1005
  3 //Author: jinjin18
  4 //Main idea: BFS
  5 //Language: C++
  6 //分为六个状态进行BFS,每有一组a,b标志为已搜过,后续出现该分支停止
  7 //用于遍历的队列元素需保存其父节点,以便找到时通过递归从头输出步骤
  8 //小技巧:可将输出的步骤保存于一个字符串数组便于记录
  9 //=======================================================================
 10 #include<stdio.h>
 11 #include<string.h>
 12 #include<map>
 13 #define MAXSIZE 100000
 14 using namespace std;
 15 struct Node{
 16     int a,b;
 17     int pre;   //便于递归逆序输出
 18     int state;  //保存该步骤的操作
 19 }Q[MAXSIZE];
 20 
 21 int last;
 22 int p ;
 23 int ca,cb,n;   //a,b的容量及目标n
 24 char outline[6][15] = {"fill A","fill B","empty A","empty B","pour A B","pour B A"};
 25 map<int,int> sign;  //也可采用sign[1000][1000],但是消耗内存比较大(还是能AC)
 26 
 27 
 28 
 29 void output(int x){                 //递归实现从头输出
 30 
 31     if(Q[x].pre!=-1){
 32         output(Q[x].pre);
 33         printf("%s\n",outline[Q[x].state]);
 34     }
 35     return;
 36 }
 37 void BFS(int a,int b){
 38     if(p > last){                   //队列中无元素返回
 39         return;
 40     }
 41     if(a == n||b == n){              //达到目标返回
 42         return ;
 43     }
 44     if(sign[a]!=b+1){              //map中存在该对则不继续搜索该分支,+1操作是为了区分b=0时与无该(a,b)的情况
 45         sign[a] = b+1;
 46         if(a < ca){               //倒满A
 47             Q[++last].a = ca;       
 48             Q[last].b = b;
 49             Q[last].state = 0;
 50             Q[last].pre = p;
 51         }
 52         if(b < cb){               //倒满B
 53             Q[++last].a = a;
 54             Q[last].b = cb;
 55             Q[last].state = 1;
 56             Q[last].pre = p;
 57         }
 58         if(a != 0){             //倒空A
 59             Q[++last].a = 0;
 60             Q[last].b = b;
 61             Q[last].state = 2;
 62             Q[last].pre = p;
 63         }
 64         if(b != 0){           //倒空B
 65             Q[++last].a = a;
 66             Q[last].b = 0;
 67             Q[last].state = 3;
 68             Q[last].pre = p;
 69         }
 70         if(a != 0&& b < cb){          //A倒到B
 71             Q[++last].a = a+b-cb > 0?a+b-cb:0;
 72             Q[last].b = a+b - Q[last].a;
 73             Q[last].state = 4;
 74             Q[last].pre = p;
 75         }
 76         if(b != 0&& a < ca){           //B倒到A
 77             Q[++last].b = a+b-ca > 0?a+b-ca:0;
 78             Q[last].a = a+b - Q[last].b;
 79             Q[last].state = 5;
 80             Q[last].pre = p;
 81         }
 82     }
 83     p++;
 84     BFS(Q[p].a,Q[p].b);       //p++不能以++p的形式写入下标中,不知道为啥
 85     return ;
 86 }
 87 
 88 
 89 void init(){
 90     sign.clear();   //清空图,其实可以保留sign[0] = 1;
 91     return ;
 92 }
 93 
 94 int main(){
 95     Q[0].pre = -1;
 96     while(scanf("%d %d %d",&ca,&cb,&n)!=EOF){
 97         //printf("inputOK\n");
 98         p = 0;
 99         last = 0;
100         init();
101         //printf("here is ok\n");
102         BFS(0,0);
103         //printf("p = %d OK\n",p);
104         //for(int i = 1;i<= p; i++){//
105             //printf("%d %d %d\n",Q[i].pre,Q[i].a,Q[i].b);
106         //}
107         output(p);
108         printf("success\n");
109 
110     }
111     return 0;
112 }
收获:通过本题对BFS搜索有了直观认识,第一次使用BFS搜索,体会到了其与DFS的不同之处,一个是队列的思想,一个是堆栈的思想。
 

猜你喜欢

转载自www.cnblogs.com/jinjin-2018/p/8963759.html
ZOJ