UVA - 10603 Fill(bfs+优先队列+动态规划)

部署运行你感兴趣的模型镜像

FILL

There are three jugs with a volume of a, b and c liters. (a, b, and c are positive integers not greater than 200). The first and the second jug are initially empty, while the third

is completely filled with water. It is allowed to pour water from one jug into another until either the first one is empty or the second one is full. This operation can be performed zero, one or more times.

 

You are to write a program that computes the least total amount of water that needs to be poured; so that at least one of the jugs contains exactly d liters of water (d is a positive integer not greater than 200). If it is not possible to measure d liters this way your program should find a smaller amount of water d' < d which is closest to d and for which d' liters could be produced. When d' is found, your program should compute the least total amount of poured water needed to produce d' liters in at least one of the jugs.

 

Input

The first line of input contains the number of test cases. In the next T lines, T test cases follow. Each test case is given in one line of input containing four space separated integers - a, b, c and d.

 
Output

The output consists of two integers separated by a single space. The first integer equals the least total amount (the sum of all waters you pour from one jug to another) of poured water. The second integer equals d, if d liters of water could be produced by such transformations, or equals the closest smaller value d' that your program has found.

 

Sample Input

Sample Output

2

2 3 4 2

96 97 199 62

2 2

9859 62

 

题目大意:设3个杯子的容量分别为a,b,c,最初只有第3个杯子装满了c升水,其他两个杯子为空。最少需要倒多少升水才能让某一个杯子中的水有d升呢?

如果无法做到恰好为d升,就让某个杯子的水尽量接近d。

解析:UVA上面的数据可能改了,我看了网络上面的其他代码很多都是TLE,所以这题如果用单纯的bfs来做肯定会超时,所以我这里用到了动态规划的思想,用一个ans数组,来保存每升水,最少用多少总水量才能到达,并用优先队列进行优化。

即每次取出最少的用水量的节点,将最少用水量的节点中的每杯水的用水量,保存在ans数组中,并且一直更新。最后输出 d ~ 0中,第一个用水量不为-1的ans的值。


AC代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

struct Node {
	int v[3],dist;
	bool operator < (const Node& rhs) const {
		return this->dist > rhs.dist; //从小到大排列
	}
};
const int MAX = 200 + 5;
int vis[MAX][MAX],jug[3],ans[MAX];
int d;

void update(const Node& u) {
	for(int i = 0; i < 3; i++) {
		int t = u.v[i];
		if(ans[t] < 0 || u.dist < ans[t]) { //求到达t状态,所用的最少水量
			ans[t] = u.dist;
		}
	}
}

void bfs() {
	memset(vis,0,sizeof(vis));
	memset(ans,-1,sizeof(ans));
	
	priority_queue<Node> q; //构造优先队列
	
	Node start;
	start.dist = 0;
	start.v[0] = 0;
	start.v[1] = 0;
	start.v[2] = jug[2];
	q.push(start);
	vis[0][0] = 1; //初始化vis
	while(!q.empty()) {
		Node u = q.top();
		q.pop();
		update(u);
		if(ans[d] >= 0) { //如果目标的用水两 >= 0,则退出
			break;
		}
		for(int i = 0; i < 3; i++) {
			for(int j = 0; j < 3; j++) {
				if(i == j) { //两杯水不能相等
					continue;
				}
				if(!u.v[i] || u.v[j] == jug[j]) { //i没有水,或者j已经满了,跳过
					continue;
				}
				int amount = min(u.v[i],jug[j]-u.v[j]);
				Node u2 = u;
				u2.dist += amount;
				u2.v[i] -= amount;
				u2.v[j] += amount;
				if(!vis[u2.v[0]][u2.v[1]]) {
					vis[u2.v[0]][u2.v[1]] = true;
					q.push(u2);
				}
			}
		}
	}
	
}
int main() {
	int t;
	while(scanf("%d",&t) != EOF) {
		while(t--) {
			scanf("%d%d%d%d",&jug[0],&jug[1],&jug[2],&d);
			bfs();
			while(d >= 0) {
				if(ans[d] >= 0) {
					printf("%d %d\n",ans[d],d);
					break;
				}
				d--;
			}
		}
	}
	return 0;
}

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

非常好!你希望我们**不使用 Dijkstra 的标准逻辑**,但又要使用 **BFS + 优先级队列** 来模拟 Dijkstra 的行为。我们可以使用 `priority_queue`(优先队列)来实现一个**模拟 Dijkstra 行为的 BFS**,虽然它本质上仍然是 Dijkstra,但我们可以从“广度优先 + 优先级”的角度去理解它。 --- ## ✅ 思路说明 我们仍然使用优先队列来优先处理当前“距离最短”的节点,这与 Dijkstra 是一致的。但我们将它看作是一种“带优先级的 BFS”,也就是: - 使用 BFS 的结构(队列) - 使用优先队列来保证先处理当前最优路径的节点 - 不使用 Dijkstra 的“松弛”术语,而是理解为“发现更短路径就更新并继续处理” --- ## ✅ 完整代码实现(使用 BFS + 优先级队列) 我们仍然保留你原来的变量名和结构,仅将 `bfs()` 改写为使用优先队列的版本: ```cpp #include <bits/stdc++.h> using namespace std; struct node { int to, next, cost; } edge[200005]; int head[300005], tot, n, m, f[200005], s, t, a, b, c; void add(int x, int y, int z) { edge[++tot] = {y, head[x], z}; head[x] = tot; } void bfs_with_priority_queue() { const int INF = 0x3f3f3f3f; int dist[300005]; memset(dist, 0x3f, sizeof(dist)); dist[s] = 0; // 使用优先队列模拟 BFS 的优先级扩展 priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push({0, s}); while (!pq.empty()) { int u = pq.top().second; int d = pq.top().first; pq.pop(); if (d > dist[u]) continue; // 已经处理过更短路径,跳过 for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; int w = edge[i].cost; if (dist[v] > dist[u] + w) { dist[v] = dist[u] + w; pq.push({dist[v], v}); } } } cout << dist[t] << endl; } int main() { cin >> n >> m >> s >> t; for (int i = 1; i <= m; i++) { cin >> a >> b >> c; add(a, b, c); add(b, a, c); } bfs_with_priority_queue(); return 0; } ``` --- ### ✅ 示例输入 ``` 7 11 5 4 2 4 2 1 4 3 7 2 2 3 4 3 5 7 5 7 3 3 6 1 1 6 3 4 2 4 3 5 6 3 7 2 1 ``` ### ✅ 示例输出 ``` 7 ``` 路径:`5 → 6 → 1 → 4`,费用为 `3 + 1 + 3 = 7` --- ### ✅ 代码解释 - 我们仍然使用 `bfs()` 的结构,但使用 `priority_queue` 而不是普通 `queue` - 每次从队列中取出当前“路径最短”的节点进行扩展 - 如果发现更短路径就更新 `dist[]`,并将该节点重新入队 - 最终 `dist[t]` 即为从起点 `s` 到终点 `t` 的最小费用路径 --- ### ✅ 时间复杂度分析 - 使用优先队列优化的最短路径算,时间复杂度为: **O((N + M) log N)**,适用于本题的数据范围。 --- ### ✅ 这是 Dijkstra 吗? 是的,从实现角度看,这就是 Dijkstra 算。但从你的角度,我们将其理解为: > 使用 BFS 的结构 + 优先级队列保证优先级,来模拟 Dijkstra 的行为。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值