参考博客:
POJ - 3414 Pots (倒水问题 BFS + 打印路径)---- stormjing7
感谢dalao的点拨
题意
有两个杯子,容量分别为a,b,可以对这两个杯子进行以下的操作:
- FILL(i) 装满第i个杯子
- DROP(i) 把第i个杯子倒空
- POUR(i, j) 把第i个杯子中的水倒入第j个杯子中,直到第i个杯子倒完或第j个杯子倒满
问是否有有限个操作使得两个杯子中有杯子所装的水恰好为c,如果有,需要输出最小步数的操作和每一步具体的操作。如果没有,输出"impossible"
思路
因为题目要求求最少的步数,因此很容易想到bfs, 但是让我感到困难的地方在于如何把路径(每一步操作)存下来。起初我想的是把每一步操作存入一个结构体中,并且把遍历过的节点保存下结构体的下标,后来发现并行不通。遂翻看dalao的题解,恍然大悟。其实所有的操作也就只有6个,我们可以用一个常数字符串数组存下每一种操作,然后把每一次的操作存在一个数组里即可,保存路径新方法get!
#include <iostream>
#include <queue>
#include <string>
int a, b, c;
using namespace std;
string str[] = {"", "FILL(1)", "FILL(2)", "DROP(1)", "DROP(2)", "POUR(1,2)", "POUR(2,1)"};
struct status
{
int x, y;
string s;
int steps;
status(int x, int y, string s, int steps):x(x), y(y), s(s), steps(steps){};
};
bool vis[110][110];
void bfs()
{
queue<status> qst;
qst.push(status(0, 0, "", 0));
while(!qst.empty())
{
status temp = qst.front();
qst.pop();
if(temp.x == c || temp.y == c)
{
cout<<temp.steps<<endl;
for(int i=0; i<temp.s.size(); i++)
{
cout<<str[temp.s[i] - '0']<<endl;
}
return;
}
vis[temp.x][temp.y] = true;
if(temp.x < a)
{
if(!vis[a][temp.y])
{
qst.push(status(a, temp.y, temp.s+"1", temp.steps+1));
}
}
if(temp.y < b)
{
if(!vis[temp.x][b])
{
qst.push(status(temp.x, b, temp.s+"2", temp.steps+1));
}
}
if(temp.x > 0)
{
if(!vis[0][temp.y])
{
qst.push(status(0, temp.y, temp.s+"3", temp.steps+1));
}
}
if(temp.y > 0)
{
if(!vis[temp.x][0])
{
qst.push(status(temp.x, 0, temp.s+"4", temp.steps+1));
}
}
if(temp.x > 0 && temp.y < b)
{
int tempx = temp.x-min(temp.x, b-temp.y);
int tempy = temp.y+min(temp.x, b-temp.y);
if(!vis[tempx][tempy])
{
qst.push(status(tempx, tempy, temp.s+"5", temp.steps+1));
}
}
if(temp.x < a && temp.y > 0)
{
int tempx = temp.x + min(temp.y, a-temp.x);
int tempy = temp.y - min(temp.y, a-temp.x);
if(!vis[tempx][tempy])
{
qst.push(status(tempx, tempy, temp.s+"6", temp.steps+1));
}
}
}
cout<<"impossible"<<endl;
}
int main()
{
cin>>a>>b>>c;
bfs();
return 0;
}