UVa10603 - Fill

来源:互联网 发布:linux服务器增加硬盘 编辑:程序博客网 时间:2024/05/16 07:54

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=841&page=show_problem&problem=1544
终于UVa好了。所以要开始整理一下我在UVa上的题目了。
这个题库主要是因为《算法入门经典》的推荐。都是英文,网上又找不到翻译所以要用起来的话除非你是学霸。要不你有一本《算法入门经典》。啦啦啦。

Problem D
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

D问题
填满
有三个罐的容积,b和c升。(a、b和c是不大于200的正整数)。第一个和第二个罐最初是空的,而第三
是完全注满水。允许从一个壶水倒入另一个,直到第一个为空或者第二个已经满了。这个操作可以执行零,一次或多次。
你要编写一个程序,计算水的总量至少需要投入,所以至少一个壶包含d升水(d是一个正整数不大于200)。如果它是不可能以这种方式衡量d升你的程序应该找到一个小水量d ’ < d这是最接近的d和d ‘升可能产生。当d ‘,你的程序应该计算总额至少倒水需要生产d ‘升的至少一个壶。
输入
输入的第一行包含测试用例的数量。未来T,T测试用例。一行中给出了每个测试用例的输入包含四个空间分离整数——,b,c和d。
输出
输出包含两个整数用一个空格隔开。第一个整数至少等于总金额(水域的总和您从一个罐子倒到另一个)倒了水。第二个整数等于d,d公升的水是否可以由这样的转换,或等于小值d ‘最接近您的程序。
样例输入
样例输出
2
2 3 4 2
96 97 199 62
2 2
9859 62

出示中英文对照。翻译来自有道。本人英语很渣。只能看刘汝佳大神的翻译了。

还是出示刘神的代码
这个算法非常直观,神似dijkstra算法。图论和搜索之间微妙的联系。

// UVa10603 Fill// Rujia Liu#include<cstdio>#include<cstring>#include<queue>using namespace std;struct Node {  int v[3], dist;  bool operator < (const Node& rhs) const {    return dist > rhs.dist;  }};const int maxn = 200 + 5;int mark[maxn][maxn], dist[maxn][maxn], cap[3], ans[maxn];void update_ans(const Node& u) {  for(int i = 0; i < 3; i++) {    int d = u.v[i];    if(ans[d] < 0 || u.dist < ans[d]) ans[d] = u.dist;  }}void solve(int a, int b, int c, int d) {  cap[0] = a; cap[1] = b; cap[2] = c;  memset(ans, -1, sizeof(ans));  memset(mark, 0, sizeof(mark));  memset(dist, -1, sizeof(dist));  priority_queue<Node> q;//优先处理倒水量最少的。  Node start;  start.dist = 0;  start.v[0] = 0; start.v[1] = 0; start.v[2] = c;//初始状态只有3号杯有水  q.push(start);  dist[0][0] = 0;  while(!q.empty()) {    Node u = q.top(); q.pop();    if(mark[u.v[0]][u.v[1]]) continue;    mark[u.v[0]][u.v[1]] = 1;    update_ans(u);    if(ans[d] >= 0) break;    for(int i = 0; i < 3; i++)      for(int j = 0; j < 3; j++) if(i != j) {        if(u.v[i] == 0 || u.v[j] == cap[j]) continue;        int amount = min(cap[j], u.v[i] + u.v[j]) - u.v[j];        Node u2;        memcpy(&u2, &u, sizeof(u));        u2.dist = u.dist + amount;        u2.v[i] -= amount;        u2.v[j] += amount;        int& D = dist[u2.v[0]][u2.v[1]];//引用,缩短代码。        if(D < 0 || u2.dist < D){          D = u2.dist;          q.push(u2);        }      }  }  while(d >= 0) {    if(ans[d] >= 0) {      printf("%d %d\n", ans[d], d);      return;    }    d--;  }}int main() {  int T, a, b, c, d;  scanf("%d", &T);  while(T--) {    scanf("%d%d%d%d", &a, &b, &c, &d);    solve(a, b, c, d);  }  return 0;}
0 0
原创粉丝点击