Pour Water

倒水问题 “fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。
Input
输入包含多组数据。每组数据输入 A, B, C 数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。
Output
你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。
Sample Input
2 7 5
2 7 4
Sample Output
fill B
pour B A
success
fill A
pour A B
fill A
pour A B
success
Notes
如果你的输出与Sample Output不同,那没关系。对于某个"A B C"本题的答案是多解的,不能通过标准的文本对比来判定你程序的正确与否。 所以本题由 SPJ(Special Judge)程序来判定你写的代码是否正确。

分析:bfs。搜索每一种状态(水量),对于每一次操作,有以下几种可能:

  1. 倒空
  2. 装满
  3. 倒向另一杯,考虑(另一杯满)和(此杯必须非空)

模拟每种可能操作,对于操作后的状态,需要判断是否已经有过这种状态,需要将已有状态记录下来,采用map<state, state> key值为操作之前的状态,value为操作之后的状态。判断和记录操作封装为refresh函数。
打印操作递归解决。
代码如下:

#include <iostream>
#include <map>
#include <queue>
using namespace std;

struct state
{
	int a, b;
	state(int A = -1,int B = -1)
	{
		a = A;
		b = B;
	}
	bool operator<(const state& rhs) const
	{
		return a != rhs.a ? a < rhs.a : b < rhs.b;
	}
};
map<state, state> from;
queue<state> q;

void print2(const state& s, const state& t)
{
	if (s.a + s.b == t.a + t.b)
		if (s.a > t.a)
			cout << "pour A B" << endl;
		else
			cout << "pour B A" << endl;

	else if(s.a + s.b < t.a + t.b)
		if (s.a < t.a)
			cout << "fill A" << endl;
		else
			cout << "fill B" << endl;

	else if(s.a + s.b > t.a + t.b)
		if (s.a > t.a)
			cout << "empty A" << endl;
		else
			cout << "empty B" << endl;
}

void print(const state& s)
{
	if (from.find(s) == from.end() || (s.a == 0 && s.b == 0))
	{
		return;
	}
	state t = from[s];
	print(t);
	print2(t, s);
	//cout << s.a << ' ' << s.b << endl;
	return;
}
void refresh(const state& s, const state& t)
{
	if (from.find(t) == from.end())
	{
		from[t] = s;
		q.push(t);
	}
}

void bfs(int A, int B, int C)
{
	q.push(state(0, 0));
	while (!q.empty())
	{
		state s = q.front();
		q.pop();
		if (s.a == C || s.b == C)
		{
			print(s);
			cout << "success" << endl;
			return;
		}
		state t;
		if (s.a > 0)
		{
			t.a = 0;
			t.b = s.b;
			refresh(s, t);
		}
		if (s.b > 0)
		{
			t.b = 0;
			t.a = s.a;
			refresh(s, t);
		}
		if (s.a < A)
		{
			t.a = A;
			t.b = s.b;
			refresh(s, t);
			if (s.b > 0)
			{
				if (s.a + s.b < A)
				{
					t.a = s.a + s.b;
					t.b = 0;
					refresh(s, t);
				}
				else
				{
					t.a = A;
					t.b = s.a + s.b - A;
					refresh(s, t);
				}
			}
		}
		if (s.b < B)
		{
			t.a = s.a;
			t.b = B;
			refresh(s, t);
			if (s.a > 0)
			{
				if (s.a + s.b < B)
				{
					t.b = s.a + s.b;
					t.a = 0;
					refresh(s, t);
				}
				else
				{
					t.b = B;
					t.a = s.a + s.b - B;
					refresh(s, t);
				}
			}
		}
	}
}
int main()
{
	int a, b, c;
	while(cin >> a >> b >> c)
		bfs(a, b, c);
}

效果如下
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值