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
2
2 3 4 2
96 97 199 62
Sample Output
2 2
9859 62
题意简述:
有三个壶,容量分别是a、b和c升,开始时候第1个和第2个壶是空的,第3个壶是满水的。可以把一个壶的水倒入另一个壶中,直到倒空或将另外一个壶倒满。输入a、b、c和d,计算最少的倒水量,使得其中一个壶里有d升水。如果不能倒出d升水的话,那么找一个最大的d'<d。输出倒水量和d,如果找不到的话输出倒水量和d'。
问题分析:
这是一个倒水问题!
将<a,b,c>看成是状态,进行状态展开搜索。开始的时候,所有水在c中,2个壶a和b都空着。过程中,可以将任何1个壶中的水倒到另外某个壶中,或将目标壶倒满,或将源壶倒空。因为壶没有刻度,只能这样。这个过程中,如果出现某个壶的水量等于d就找到解了。同时,也要考虑得不到d的情况,所以过程中需要将最大的d'<d记录下来。容器间水倒来倒去,每次有6种倒法,对这6种倒法进行试探即可。求的是倒水量最小,所以用分支限界法实现,倒水量最小的状态优先展开。
程序说明:
搜索过的状态就不需要再搜索了,用数组notvist[][][]来标记搜索过的状态。
这个问题的程序是先CV来的,然后做了适当的修改,参见参考链接。
参考链接:HDU1495非常可乐
题记:
优秀的程序员一定是CV大师。能CV则CV的做法,可以省去许多编码和测试的时间。但是,如果出现小错误的话,找起来一样的费时。
AC的C++语言程序如下:
/* UVA10603 Fill */
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 200;
int a, b, c, d, maxd1, minamount;
bool notvist[MAXN+1][MAXN+1][MAXN+1];
struct node {
int a, b, c, amount;
bool operator < (const node& n) const {
return amount > n.amount;
}
};
int bfs()
{
maxd1 = 0;
minamount = 0;
priority_queue<node> q;
memset(notvist, true, sizeof(notvist));
node f, v;
f.c = c;
f.a = 0;
f.b = 0;
f.amount=0;
q.push(f);
notvist[f.c][f.a][f.b] = false;
while(!q.empty()) {
f = q.top();
q.pop();
if(f.a == d || f.b == d || f.c == d)
return f.amount;
if(f.a < d && f.a > maxd1) {
maxd1 = f.a;
minamount = f.amount;
}
if(f.b < d && f.b > maxd1) {
maxd1 = f.b;
minamount = f.amount;
}
if(f.c < d && f.c > maxd1) {
maxd1 = f.c;
minamount = f.amount;
}
// c --> a
if(f.c && a - f.a > 0) {
if(f.c > a - f.a) { // c > a的剩余容量
v.c = f.c - (a - f.a);
v.a = a;
v.b = f.b;
v.amount = f.amount + (a - f.a);
} else { // c <= a的剩余容量
v.c = 0;
v.a = f.a + f.c;
v.b = f.b;
v.amount = f.amount + f.c;
}
if(notvist[v.c][v.a][v.b]) {
notvist[v.c][v.a][v.b] = false;
q.push(v);
}
}
// c --> b
if(f.c && b - f.b > 0) {
if(f.c > b - f.b) { // c > b的剩余容量
v.c = f.c - (b - f.b);
v.a = f.a;
v.b = b;
v.amount = f.amount + (b - f.b);
} else { // c <= b的剩余容量
v.c = 0;
v.a = f.a;
v.b = f.b + f.c;
v.amount = f.amount + f.c;
}
if(notvist[v.c][v.a][v.b]) {
notvist[v.c][v.a][v.b] = false;
q.push(v);
}
}
// a --> c
if(f.a && c - f.c > 0) {
if(f.a > c - f.c) { // a > c的剩余容量
v.c = c;
v.a = f.a - (c - f.c);
v.b = f.b;
v.amount = f.amount + (c - f.c);
} else { // a <= c的剩余容量
v.c = f.c + f.a;
v.a = 0;
v.b = f.b;
v.amount = f.amount + f.a;
}
if(notvist[v.c][v.a][v.b]) {
notvist[v.c][v.a][v.b] = false;
q.push(v);
}
}
// a --> b
if(f.a && b - f.b > 0) {
if(f.a > b - f.b) { // a > b的剩余容量
v.c = f.c;
v.a = f.a - (b - f.b);
v.b = b;
v.amount = f.amount + (b - f.b);
} else { // a <= b的剩余容量
v.c = f.c;
v.a = 0;
v.b = f.b + f.a;
v.amount = f.amount + f.a;
}
if(notvist[v.c][v.a][v.b]) {
notvist[v.c][v.a][v.b] = false;
q.push(v);
}
}
// b --> c
if(f.b && c - f.c > 0) {
if(f.b > c - f.c) { // b > c的剩余容量
v.c = c;
v.a = f.a;
v.b = f.b - (c - f.c);
v.amount = f.amount + (c - f.c);
} else { // b <= c的剩余容量
v.c = f.c + f.b;
v.a = f.a;
v.b = 0;
v.amount = f.amount + f.b;
}
if(notvist[v.c][v.a][v.b]) {
notvist[v.c][v.a][v.b] = false;
q.push(v);
}
}
// b --> a
if(f.b && a - f.a > 0) {
if(f.b > a - f.a) { // b > a的剩余容量
v.c = f.c;
v.a = a;
v.b = f.b - (a - f.a);
v.amount = f.amount + (a - f.a);
} else { // b <= a的剩余容量
v.c = f.c;
v.a = f.a + f.b;
v.b = 0;
v.amount = f.amount + f.b;
}
if(notvist[v.c][v.a][v.b]) {
notvist[v.c][v.a][v.b] = false;
q.push(v);
}
}
}
return -1;
}
int main()
{
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d%d%d", &a, &b, &c, &d);
int ans = bfs();
if(ans < 0) {
printf("%d %d\n", minamount, maxd1);
} else
printf("%d %d\n", ans, d);
}
return 0;
}