优秀的程序员一定是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 ", minamount, maxd1); } else printf("%d %d ", ans, d); } return 0; }