【B - Pour Water】倒水问题

题意:

有三个已知容量的杯子A,B,C,利用A杯和B杯来回倒水使任意一个杯子正好包含C单位的水。

“fill A ”表示倒满A杯,“empty A”表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或把A杯倒空。

输出整个倒水过程,最后输出“ success ”。

样例输入:
在这里插入图片描述
样例输出:
在这里插入图片描述

思路:

倒水的过程其实是A杯和B杯从一个状态变化到另一个状态,最后达到一个目标状态的过程。可以把每一个状态抽象为一个点,x代表A杯,y代表B杯。整个过程简化为从(0,0)变化到(x,C)或(C,y)。

利用bfs方法求解,当前节点一步操作可以走到哪些点取决于题目操作。例如当前点是(a,b),则一步操作可以走到的点有:倒空A杯的水(0,b),倒空B杯的水(a,0),倒满A杯(A,b),倒满B杯(a,B),A杯倒向B杯(0,a+b)或(a+b-B,B),B杯倒向A杯(a+b,0)或(A,a+b-A)。

记录每个点的前序点,最后根据两点的状态求出当前操作。

总结:

求解从一个状态的到另一个状态的过程问题,可以考虑bfs方法,并且可以保证这个过程最简短。

一定要注意开的二维数组的大小是[A+1][B+1],因为有倒空和倒满两种状态,否则会发生数组越界。

输出过程print也可以不存入数组,递归到起点然后再输出也是一个很好的方法。输出时判断两个状态之间的操作过程judge此处写的是复杂的。

代码:

#include<iostream>
#include<queue>
#include <map>
using namespace std;
struct point
{
	int a;
	int b;
	point(int a, int b)
	{
		this->a = a;
		this->b = b;
	}
	point(){}
};
point** before; //(当前状态,前一状态)
queue<point> way;
void judge(point& s, point& t, int A, int B)//判断操作
{
	if (s.a > 0 && t.a == 0 && t.b == s.b)
		cout << "empty A" << endl;
	else if (t.a == s.a && s.b > 0 && t.b == 0)
		cout << "empty B" << endl;
	else if (s.a < A && t.a == A && t.b == s.b)
		cout << "fill A" << endl;
	else if (s.b < B && t.b == B && t.a == s.a)
		cout << "fill B" << endl;
	else if (s.a < A && s.b != 0)
		cout << "pour B A" << endl;
	else if (s.b < B && s.a != 0)
		cout << "pour A B" << endl;
}
void print(point t, int A, int B)//输出过程
{
	point* path;
	path = new point[(A + 1) * (B + 1)];
	int m = 0;
	while (t.a != 0 || t.b!=0)
	{
		path[m] = t;
		t = before[t.a][t.b];
		m++;
	}
	path[m] = t;
	m++;
	for (int i = m - 1; i >0 ; i--)
		judge(path[i], path[i - 1], A, B);
	cout << "success" << endl;
}
void change(point& s, point& t)//记录前序点
{
	if (before[t.a][t.b].a == -1)
	{
		before[t.a][t.b] = s;
		way.push(t);
	}
}
void bfs(int A, int B, int C)
{
	point p(-1, -1);
	for (int i = 0; i <= A; i++)//初始化前序点数组
		for (int j = 0; j <= B; j++)
			before[i][j] = p;
	while (!way.empty())//清空队列
	{
		way.pop();
	}
	point s, t;
	s.a = 0;
	s.b = 0;
	way.push(s);
	before[s.a][s.b] = s;
	while (!way.empty())
	{
		s = way.front();
		way.pop();
		if (s.a == C || s.b == C)//特判终点
		{
			print(s, A, B);
			return;
		}
		//倒空a杯的水
		if (s.a > 0)
		{
			t.a = 0;
			t.b = s.b;
			change(s, t);
		}
		//倒空b杯的水
		if (s.b > 0)
		{
			t.a = s.a;
			t.b = 0;
			change(s, t);
		}
		//a杯未满,蓄满a杯
		if (s.a < A)
		{
			t.a = A;
			t.b = s.b;
			change(s, t);
			//考虑倒入
			if (s.b != 0)//pour B A
			{
				if (s.a + s.b <= A)
				{
					t.a = s.a + s.b;
					t.b = 0;
					change(s, t);
				}
				else//倒满a杯
				{
					t.a = A;
					t.b = s.a + s.b - A;
					change(s, t);
				}
			}
		}
		//b杯未满,蓄满b杯
		if (s.b < B)
		{
			t.a = s.a;
			t.b = B;
			change(s, t);
			//考虑倒入
			if (s.a != 0)//pour A B
			{
				if (s.a + s.b <= B)
				{
					t.a = 0;
					t.b = s.a + s.b;
					change(s, t);
				}
				else
				{
					t.a = s.a + s.b - B;
					t.b = B;
					change(s, t);
				}
			}
		}
	}
}
int main()
{
	int A, B, C;
	while (cin >> A)
	{
		cin >> B;
		cin >> C;
		before = new point * [A + 1];
		for (int i = 0; i < A + 1; i++)
			before[i] = new point[B + 1];
		bfs(A, B, C);
	}
}
发布了5 篇原创文章 · 获赞 4 · 访问量 98

猜你喜欢

转载自blog.csdn.net/qq_44047415/article/details/104654886
今日推荐