优秀的程序员一定是CV大师。能CV则CV的做法,可以省去许多编码和测试的时间。但是,如果出现小错误的话,找起来一样的费时。
问题链接:UVA10603 Fill。
题意简述:有三个壶,容量分别是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非常可乐,也是一个倒水问题,只不过输入、输出以及限制条件不一样。
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;
}