三个水杯倒水问题

解题思路
对于每个杯子,它都有两种倒水的操作,如A、B、C三个杯子。要倒出A杯中的水,可以倒给B杯也可以倒给C杯。即共有六种倒水的操作。
那么可以得到一个解空间树的题。树的每一个节点便是当前三个杯子中的水量。当一个节点的水量为目的水量的时候就结束。
因为对三个杯子有六种操作,也就是说可能有六种状态,记住只是可能。也就是说每一个节点可最多以衍生六个节点。
而开始状态就是树的根节点。
既然当某一个节点状态与目的状态相同时候可以结束空间树了,那么若是无法达到目的状态如何结束空间树的衍生呢?
可以用宽度优先搜索,因为每次是以一个节点衍生出最多六个节点,每次衍生的时候取出队列里的第一个数开始衍生节点。
把每次衍生的节点再压入队列里面,直到队列为空就停止。
注: 每次衍生节点的时候,还需要判断衍生出来的节点状态是否已经出现过,固然需要一个三维的标记数组。
空间树的结构自己可以动手去画,每个节点是A、B、C三个杯子的当前水量。
对该题详细讲解博客地址:http://blog.csdn.net/code_pang/article/details/7802944
此题代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 110; 4 int mark[maxn][maxn][maxn]; 5 int InitCup[3], TargetCup[3]; 6 struct Node 7 { 8 int state[3]; 9 int step; 10 }; 11 12 //检测节点是否是目的节点 13 bool checkTarget(Node a); 14 //倒水操作,Start为要倒给其他杯子水,End为要水的杯子 15 void pourwater(int Start, int End, Node &cup); 16 //宽度优先搜索函数 17 int bfs(); 18 19 int main() 20 { 21 int tcase; 22 cin>>tcase; 23 while(tcase--) 24 { 25 for(int i=0; i<3; i++) cin>>InitCup[i]; 26 for(int i=0; i<3; i++) cin>>TargetCup[i]; 27 cout<<bfs()<<endl; 28 } 29 return 0; 30 } 31 bool checkTarget(Node a) 32 { 33 for(int i=0; i<3; i++) 34 { 35 if(a.state[i] != TargetCup[i]) 36 return false; 37 } 38 return true; 39 } 40 41 void pourwater(int Start, int End, Node &cup) 42 { 43 int needwater = InitCup[End] - cup.state[End]; 44 if(cup.state[Start] > needwater) 45 { 46 cup.state[Start] -= needwater; 47 cup.state[End] = InitCup[End]; 48 } 49 else{ 50 cup.state[End] += cup.state[Start]; 51 cup.state[Start] = 0; 52 } 53 //倒水完后,操作加一 54 cup.step++; 55 } 56 57 int bfs() 58 { 59 //声明根节点,与状态节点队列 60 Node root; 61 queue<Node> State; 62 memset(mark, 0, sizeof(mark)); 63 //开始的时候,根节点只有第一个杯子有水。 64 root.state[0] = InitCup[0]; 65 root.state[1] = root.state[2] = 0; 66 root.step = 0; 67 68 State.push(root); 69 //标记当前状态,以后衍生出此状态的节点不用再次压入队列 70 mark[root.state[0]][0][0] = 1; 71 72 while(State.size()) 73 { 74 Node father = State.front(); 75 State.pop(); 76 if(checkTarget(father)) 77 return father.step; 78 79 //开始根据父节点father衍生六个子节点 80 for(int Startcup=0; Startcup<3; Startcup++){ 81 for(int step=1; step<3; step++){ 82 int Endcup = (Startcup+step)%3; 83 //临时存储原来的三个杯子状态Cup 84 Node Cup = father; 85 //判断是否应该倒水,当倒出水的杯子有水且要倒的杯子里水没满时候可以执行 86 if( Cup.state[Startcup] != 0 && Cup.state[Endcup] < InitCup[Endcup]){ 87 //倒水操作 88 pourwater(Startcup, Endcup, Cup); 89 90 //判断当前的状态是否压入过队列中,没有则压入队列中 91 if(mark[Cup.state[0]][Cup.state[1]][Cup.state[2]] == 0){ 92 mark[Cup.state[0]][Cup.state[1]][Cup.state[2]] = 1; 93 State.push(Cup); 94 }//if-mark 95 }//if-Cup 96 }//for-step 97 }//for-Start-cup 98 }//while 99 return -1; 100 }

浙公网安备 33010602011771号