倒水问题

题意:

有无限量的水,以及容量为ab的两只杯子,要求通过两只杯子得到c单位的水。
输入包含若干组数据,每组输入abc,要求输出得到c单位水需要进行的操作顺序,并且在成功得到c单位水后输出success
一共有包含六种操作:

1、倒满A杯(fill A)
2、倒满B杯(fill B)
3、倒空A杯(empty A)
4、倒空B杯(empty B)
5、把A的水倒到B杯并把A杯倒空或把B杯倒满(pour A B)
6、把B的水倒到A杯并把B杯倒空或把A杯倒满(pour B A)
输入样例:
2 7 5
2 7 4
输出样例
fill B
pour B A
success 
fill A
pour A B
fill A
pour A B
success

思路:

1、构造一个结构体status,有a,b两个元素以及六种操作对应的函数。
2、声明map<status, bool> mp,用来判断是否到过status对应的情况,分别对应true和false;map<status, status> from,用来记录某status情况对应的前驱status,可以通过from[status]得到某status前驱状态。
3、使用bfs操作:首先将起始a=0b=0status插入队列中,每次取出队列中一个元素now,就对其进行六种操作,并且将操作结果插入队列中。循环直至队列清空或者now.a=c或者now.b=c,并将now作为bfs的返回值。
4、从bfs函数返回得到的status型数据,循环通过from[status]找到前驱状态,并且根据两者状态判断进行的操作并记录,直至前驱状态为status(0,0)。最后顺序输出所有操作即可。

需要注意的是:

由于输入时可能包含多组数据,所以在完成一组数据的输出后,需要将队列、map等容器清空,否则会影响到下一组数据的操作。

代码:

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

string operation[] = { "fill A","fill B","empty A","empty B","pour A B","pour B A" };
int aRemain, bRemain;
int aMax, bMax;


struct status {
	int a, b;
	status() {}
	status(int dx, int dy) {
		a = dx;
		b = dy;
	}
	bool operator < (const status &s) const {
		return a != s.a ? a < s.a : b < s.b;
	}
	bool operator == (const status &s) const {
		return a == s.a&&b == s.b;
	}
	status filla() {
		return status(aMax, b);
	}
	status fillb() {
		return status(a, bMax);
	}
	status emptya() {
		return status(0, b);
	}
	status emptyb() {
		return status(a, 0);
	}
	status pourab() {
		if (a > bMax - b) {
			return status(a - bMax + b, bMax);
		}
		else {
			return status(0, a + b);
		}
	}
	status pourba() {
		if (b > aMax - a) {
			return status(aMax, b - aMax + a);
		}
		else {
			return status(0, b + a);
		}
	}
};

queue<status> q;
map<status, bool> mp;//用来判断是否到过status对应的情况
map<status, status> from;//用来记录status的前驱<后,前>

void did(status x, status y) {
	if (mp[x] == 0) {
		mp[x] = 1;
		from[x] = y;
		q.push(x);
	}
}

status bfs(int a, int b, int c) {
	status t(0, 0);
	q.push(t);
	mp[t] = 1;
	while (!q.empty()) {
		status now = q.front();
		q.pop();
		if (now.a == c || now.b == c) {
			return now;
		}

		did(now.filla(), now);
		did(now.fillb(), now);
		did(now.emptya(), now);
		did(now.emptyb(), now);
		did(now.pourab(), now);
		did(now.pourba(), now);
	}
}

int main()
{
	int c;
	while (cin >> aMax >> bMax >> c) {
		status now = bfs(aMax, bMax, c);
		cout << now.a << " " << now.b << endl;
		vector<int> vec;
		int i = 0;
		while (now.a != 0 || now.b != 0) {
			status pre = from[now];
			//0.fill A
			if (pre.b == now.b&&now.a == aMax) {//a不变b归零
				vec.push_back(0);
			}
			//1.fill B
			if (pre.a == now.a&&now.b == bMax) {
				vec.push_back(1);
			}
			//2.empty A
			if (pre.b == now.b&&now.a == 0) {
				vec.push_back(2);
			}
			//3.empty B
			if (pre.a == now.a&&now.b == 0) {
				vec.push_back(3);
			}
			//4.pour A B
			if (pre.a > now.a&&pre.b < now.b) {
				vec.push_back(4);
			}
			//5.pour B A
			if (pre.a < now.a&&pre.b > now.b) {
				vec.push_back(5);
			}
			i++;
			now = pre;
		}
		for (int j = i - 1; j >= 0; j--) {
			cout << operation[vec[j]] << endl;
		}
		cout << "success" << endl;
		mp.clear();
		from.clear();
		vec.clear();
	}
}```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值