倒牛奶的问题, 开始看感觉跟倒水的问题很像, 想直接找规律, 写个类似于循环取余的代码。 但后来发现不行,因为这道题有三个桶,水量也是有限制的。只好用模拟的方法把所有的情况都试一遍。
建一个state[21][21][21]的数组存储出现过的状态。对于遍历状态,对每一种状态, 分别采用六种处理方法,若有新状态出现这将新状态置为1,同时标记flag++;若所有循环之后,flag == 0, 就说明遍历完成了。
开始脑子抽筋了, 写了个多出口的程序, 显然是错的。如下:
int mothersmilk(int a, int b, int c) { int aa, bb, cc; int flag = 0; aa = a, bb = b, cc = c; pour(&aa, A, &bb, B); if(state[aa][bb][cc] != 1) { state[aa][bb][cc] = 1; mothersmilk(aa, bb, cc); // flag++; } aa = a, bb = b, cc = c; pour(&bb, B, &aa, A); if(state[aa][bb][cc] != 1) { state[aa][bb][cc] = 1; mothersmilk(aa, bb, cc); } aa = a, bb = b, cc = c; pour(&aa, A, &cc, C); if(state[aa][bb][cc] != 1) { state[aa][bb][cc] = 1; mothersmilk(aa, bb, cc); // } aa = a, bb = b, cc = c; pour(&cc, C, &aa, A); if(state[aa][bb][cc] != 1) { state[aa][bb][cc] = 1; mothersmilk(aa, bb, cc); } aa = a, bb = b, cc = c; pour(&bb, B, &cc, C); if(state[aa][bb][cc] != 1) { state[aa][bb][cc] = 1; mothersmilk(aa, bb, cc); // } aa = a, bb = b, cc = c; pour(&cc, C, &bb, B); if(state[aa][bb][cc] != 1) { state[aa][bb][cc] = 1; mothersmilk(aa, bb, cc); // }
return 0; //... }
错误的原因在于,若是第一个if语句中的mothersmilk操作完了,一定会返回0,那后面的语句都起不到作用了。
后来发现,可以直接对所有的state变量循环,用for语句,逻辑就清楚多了,提交也AC了。正确的代码:
/* ID: 13012131 LANG: C TASK: milk3 */ #include <stdio.h> #include <assert.h> int state[21][21][21]; //存储状态 出现过为1 未出现过为0 int A, B, C; int pour(int *a, int fulla, int *b, int fullb) //a向b倒水 { if(*b == fullb || *a == 0) //若a没水 或 b满 a不能向b倒水 状态不变 { return 1; } if(*b != fullb) //b不满 { if(*a <= fullb - *b) //a倒光 { *b = *b + *a; *a = 0; } else //b倒满 { *a = *a - (fullb - *b); *b = fullb; } } return 0; } int main() { FILE *in, *out; in = fopen("milk3.in", "r"); out = fopen("milk3.out", "w"); int ans[21] = {0}; int i, j ,k; fscanf(in, "%d %d %d", &A, &B, &C); for(i = 0; i <= 20; i++) { for(j = 0; j <= 20; j++) { for(k = 0; k <= 20; k++) { state[i][j][k] = 0; } } } state[0][0][C] = 1; int flag = 0; do{ flag = 0; //注意:flag一定要写在这里 因为在扩展过程中,需要对state的所有状态循环多次 以防止在大序号状态下扩展了小序号状态 比如 2 0 8 扩展为 0 2 8 因为0 2 8的状态已经超过了 所以还要重新遍历一遍才可以 for(i = 0; i <= A; i++) { for(j = 0; j <= B; j++) { for(k = 0; k <= C; k++) { if(state[i][j][k] == 1) { int aa, bb, cc; aa = i, bb = j, cc = k; pour(&aa, A, &bb, B); if(state[aa][bb][cc] == 0) { state[aa][bb][cc] = 1; flag++; } aa = i, bb = j, cc = k; pour(&bb, B, &aa, A); if(state[aa][bb][cc] == 0) { state[aa][bb][cc] = 1; flag++; } aa = i, bb = j, cc = k; pour(&aa, A, &cc, C); if(state[aa][bb][cc] == 0) { state[aa][bb][cc] = 1; flag++; } aa = i, bb = j, cc = k; pour(&cc, C, &aa, A); if(state[aa][bb][cc] == 0) { state[aa][bb][cc] = 1; flag++; } aa = i, bb = j, cc = k; pour(&bb, B, &cc, C); if(state[aa][bb][cc] == 0) { state[aa][bb][cc] = 1; flag++; } aa = i, bb = j, cc = k; pour(&cc, C, &bb, B); if(state[aa][bb][cc] == 0) { state[aa][bb][cc] = 1; flag++; } state[i][j][k]++; } } } } }while(flag > 0); for(j = 0; j <= 20; j++) { for(k = 0; k <= 20; k++) { if(state[0][j][k] != 0 && ans[k] == 0) { ans[k] = 1; } } } for(i = 0; i < C; i++) { if(ans[i] == 1) { fprintf(out, "%d ", i); } } fprintf(out, "%d\n", C); return 0; }