UVA10603 倒水问题

题意给出3个杯子,只有最后一个杯子装满水,问至少倒多少水才能使其中一个杯子里的水达到d升。

分析:这题关键在于优先级队列,每次都要取倒水量最小的状态出来。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<queue>
using namespace std;
struct Node {
	int v[3], dist;
	bool operator<(const Node& u) const{
		return dist > u.dist;
	}
};
const int maxn = 200 + 5;
int vis[maxn][maxn], cap[3], ans[maxn];
void bfs(int a, int b, int c, int d) {
	priority_queue<Node>q;//优先级队列
	memset(vis, 0, sizeof(vis));
	memset(ans, -1, sizeof(ans));
	cap[0] = a, cap[1] = b, cap[2] = c;
	Node start;
	start.dist = 0;
	start.v[0] = 0; start.v[1] = 0; start.v[2] = c;
	q.push(start);
	vis[0][0] = 1;
	while (!q.empty()) {
		Node u = q.top(); q.pop();
		for (int i = 0; i < 3; i++) {
			int d = u.v[i];
			if (ans[d]<0 || ans[d]>u.dist)ans[d] = u.dist;//更新每个杯子水的状态信息
		}
		if (ans[d] >= 0)break;//有目标状态信息,退出
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				if (u.v[i] == 0 || u.v[j] == cap[j])continue;//杯子满了或者空了
				int amount = min(cap[j], u.v[j] + u.v[i]) - u.v[j];//加水量最小
				Node u2;
				memcpy(&u2, &u, sizeof(u));
				u2.dist = u.dist + amount;//u2的倒水量
				u2.v[i] -= amount;
				u2.v[j] += amount;
				if (!vis[u2.v[0]][u2.v[1]]) {
					vis[u2.v[0]][u2.v[1]] = 1;
					q.push(u2);
				}
			}
		}

	}
	while (d >= 0) {
		if (ans[d] >= 0) {
			printf("%d %d\n",ans[d], d);
			return;
		}
		d--;
	}
}
int main() {
	int kase,a,b,c,d;
	cin >> kase;
	while (kase-- > 0) {
		cin >> a >> b >> c >> d;
		bfs(a, b, c, d);
	}
	//system("pause");
	return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_36973725/article/details/84018009