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

来源:互联网 发布:linux获得root权限 编辑:程序博客网 时间:2024/06/15 13:53

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; //初始化viswhile(!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;}

0 0