solve a b g | g ‘mod‘ d /= 0 = [] -- no solution
| otherwise = solve’ (x ∗ g ‘div‘ d)
where
(d, x, y) = extGcd a b
solve’ x | x < 0 = solve’ (x + b)
| otherwise = pour x [(0, 0)]
pour 0 ps = reverse ((0, g):ps)
pour x ps@((a’, b’):_) | a’ = 0 = pour (x - 1) ((a, b’):ps) -- fill a
| b’ = b = pour x ((a’, 0):ps) -- empty b
| otherwise = pour x ((max 0 (a’ + b’ - b),min (a’ + b’) b):ps)
这一方法的最大优越性是在速度上远远快于基于暴力搜索的BFS解法。但是并不保证操作次数是最少的。如果要想获得最少的操作次数,需要使得|x| + |y|最小,这个并不难实现。
对应的BFS解法的C代码如下:
#include <stdio.h>
#include <stdlib.h>
int min(int a, int b) { return a <= b ? a : b; }
int max(int a, int b) { return b < a ? a : b; }
struct Step {
int p, q;
struct Step* parent;
};
struct Step* make_step(int p, int q, struct Step* parent) {
struct Step* s = (struct Step*) malloc(sizeof(struct Step));
s->p = p;
s->q = q;
s->parent = parent;
return s;
}
struct Step *steps[1000], **head, **tail = steps;
void push(struct Step* s) { *tail++ = s; }
struct Step* pop() { return *head++; }
int empty() { return head == tail; }
void reset() {
struct Step **p;
for (p = steps; p != tail; ++p)
free(*p);
head = tail = steps;
}
int eq(struct Step* a, struct Step* b) {
return a->p == b->p && a->q == b->q;
}
int visited(struct Step* s) {
struct Step **p;
for (p = steps; p != tail; ++p)
if (eq(*p, s)) return 1;
return 0;
}
void expand(struct Step* s, int a, int b, struct Step** cs) {
int p = s->p, q = s->q;
cs[0] = make_step(a, q, s); /*fill A*/
cs[1] = make_step(p, b, s); /*fill B*/
cs[2] = make_step(0, q, s); /*empty A*/
cs[3] = make_step(p, 0, s); /*empty B*/
cs[4] = make_step(max(0, p + q - b), min(p + q, b), s); /*pour A into B*/
cs[5] = make_step(min(p + q, a), max(0, p + q - a), s); /*pour B into A*/
}
struct Step* solve(int a, int b, int g) {
int i;
struct Step *cur, *cs[6];
reset();
push(make_step(0, 0, NULL));
while (!empty()) {
cur = pop();
if (cur->p == g || cur->q == g)
return cur;
else {
expand(cur, a, b, cs);
for (i = 0; i < 6; ++i)
if(!eq(cur, cs[i]) && !visited(cs[i]))
push(cs[i]);
}
}
return NULL;
}
/**print the steps in reverse order, returns how many steps there are. */
int print(struct Step* s) {
int n = -1;
if (s) {
n = 1 + print(s->parent);
printf("%d, %d\n", s->p, s->q);
}
return n;
}
void test(int a, int b, int g) {
printf("solve a=%d, b=%d, g=%d:\n", a, b, g);
printf("total %d steps\n", print(solve(a, b, g)));
reset();
}
int main(int argc, char *argv[]) {
test(3, 5, 4);
test(4, 9, 6);
return 0;
}