这一题运用广度优先搜索可以解决,主要是各个状态的转移以及某个状态出现过要标记,避免重复,进入死循环。
下面是AC代码,上面有详细的讲解:
# include <iostream> # include <cstring> # include <queue> using namespace std; class data //队列的结点, { public: int water[3]; //三个水杯的状态 int step; //步骤 }; bool visited[100][100][100]; //标记三个水杯的状态,避免重复 int start[3], end[3]; //输入的开始状态和结束状态 int main() { int BFS(); int n; cin >> n; while(n--) { cin >> start[0] >> start[1] >> start[2]; cin >> end[0] >> end[1] >> end[2]; int k = BFS(); cout << k << endl; } return 0; } int Achieve(data node) //判断是否到达结束状态 { for(int i = 0; i < 3; i++) { if(node.water[i] != end[i]) return 0; } return 1; } int BFS() //广度优先搜索 { int i, j; queue <data> Que; //创建队列 memset(visited, false, sizeof(visited)); //初始化visited数组 data s1; //开始结点 s1.water[0] = start[0]; //第一个杯子 s1.water[1] = 0; //第二个杯子 s1.water[2] = 0; //第三个杯子 s1.step = 0; //步数 Que.push(s1); //进队列 visited[start[0]][0][0] = true; //标记该状态出现过 while(!Que.empty()) //判断队列是否为空 { s1 = Que.front(); //从队列中获取队头 Que.pop(); if(Achieve(s1)) //到达结束状态,返回步数 return s1.step; for(i = 0; i < 3; i++) //从i号杯子到往另外两个杯子中放水。 { //i为倒水的杯子,j为接水的杯子 for(j = 0; j < 3; j++) { if(j == i) //i=j,杯子相同,只能往另外的杯子倒水 continue; if(s1.water[i] != 0 && s1.water[j] < start[j]) //倒水的杯子必须有水且接水的杯子水量不能超过容量 { data node; node = s1; int pour = start[j] - node.water[j]; //要倒的水量 if(node.water[i] >= pour) //倒水的杯子的水量大于等于pour,倒水的杯子不会倒空 { node.water[j] += pour; node.water[i] -= pour; } else //倒空的情况 { node.water[j] += node.water[i]; node.water[i] = 0; } node.step = s1.step + 1; //步数加一 if(!visited[node.water[0]][node.water[1]][node.water[2]]) //判断该状态是否出现过 { visited[node.water[0]][node.water[1]][node.water[2]] = true; Que.push(node); } } } } } return -1; //不能实现,返回-1; }
很容易看得懂的,慢慢理解,细细体会。
时间: 2024-10-13 02:01:39