1. 用dfs,[A][B][C]为三个状态,且只有6个操作,a倒b,a倒c,b倒a,b倒c,c倒a,c倒b。知道用深搜了,但是还是不知道怎么写,看了别人的代码,才会写dfs()这个函数了。其实确定深搜了之后,写这个函数的时候,不需要考虑递归是怎么进行的,只需要考虑这次和下一次的操作过程即可。
2. 以下是代码:
/* ID: dollar4 PROG: milk3 LANG: C++ */ #include <iostream> #include <fstream> #include <string> #include <algorithm> #include <cstring> using namespace std; int a, b, c, p = 0, isin[20]; int vis[21][21][21]; int ans[21]; bool cmp(int a, int b) { return a < b; } void dfs(int aa, int bb, int cc) { if (vis[aa][bb][cc]) return; vis[aa][bb][cc] = 1; if (aa == 0 && !isin[cc]) { isin[cc] = 1; ans[p++] = cc; } if (aa >= b - bb)//a->b dfs(aa - b + bb, b, cc); else dfs(0, bb + aa, cc); if (bb >= a - aa)// b->a dfs(a, bb - a + aa, cc); else dfs(aa + bb, 0, cc); if (cc >= b - bb) // c->b dfs(aa, b, cc - b + bb); else dfs(aa, bb + cc, 0); if (cc >= a - aa) // c->a dfs(a, bb, cc - a + aa); else dfs(aa + cc, bb, 0); if (aa >= c - cc) // a->c dfs(aa - c + cc, bb, c); else dfs(0, bb, cc + aa); if (bb >= c - cc) // b->c dfs(aa, bb - c + cc, c); else dfs(aa, 0, cc + bb); return; } int main() { ofstream fout ("milk3.out"); ifstream fin ("milk3.in"); memset(vis, 0, sizeof(vis)); memset(isin, 0, sizeof(isin)); memset(ans, 0, sizeof(ans)); fin >> a >> b >> c; dfs(0, 0, c); sort(ans, ans + p, cmp); int cnt = p - 1; for (int i = 0; i < p; i++) { fout << ans[i]; if (cnt--) fout << ' '; else fout << endl; } return 0; }
We use a simple depth-first search to find all the possible states for the three buckets, pruning the search by not researching from states we've seen before.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <ctype.h> #define MAX 20 typedef struct State State; struct State { int a[3]; }; int seen[MAX+1][MAX+1][MAX+1]; int canget[MAX+1]; State state(int a, int b, int c) { State s; s.a[0] = a; s.a[1] = b; s.a[2] = c; return s; } int cap[3]; /* pour from bucket "from" to bucket "to" */ State pour(State s, int from, int to) { int amt; amt = s.a[from]; if(s.a[to]+amt > cap[to]) amt = cap[to] - s.a[to]; s.a[from] -= amt; s.a[to] += amt; return s; } void search(State s) { int i, j; if(seen[s.a[0]][s.a[1]][s.a[2]]) return; seen[s.a[0]][s.a[1]][s.a[2]] = 1; if(s.a[0] == 0) /* bucket A empty */ canget[s.a[2]] = 1; for(i=0; i<3; i++) for(j=0; j<3; j++) search(pour(s, i, j)); } void main(void) { int i; FILE *fin, *fout; char *sep; fin = fopen("milk3.in", "r"); fout = fopen("milk3.out", "w"); assert(fin != NULL && fout != NULL); fscanf(fin, "%d %d %d", &cap[0], &cap[1], &cap[2]); search(state(0, 0, cap[2])); sep = ""; for(i=0; i<=cap[2]; i++) { if(canget[i]) { fprintf(fout, "%s%d", sep, i); sep = " "; } } fprintf(fout, "\n"); exit(0); }
#include<stdio.h> int m[21][21][21]; int poss[21]; int A, B, C; int main(void) { int i,j,k; int flag; FILE* in=fopen("milk3.in","r"); fscanf(in, "%d %d %d",&A, &B, &C); fclose(in); for(i=0;i<21;i++) for(j=0;j<21;j++) for(k=0;k<21;k++) m[i][j][k]=0; for(i=0;i<21;i++) poss[i]=0; m[0][0][C]=1; for(flag=1;flag;) { flag=0; for(i=0;i<=A;i++) for(j=0;j<=B;j++) for(k=0;k<=C;k++) { if(m[i][j][k]) { if(i==0) poss[k]=1; if(i) { if(j<B) { if(B-j>=i) { if( m[0][j+i][k]==0) { m[0][j+i][k]=1; flag=1; } } else { if( m[i-(B-j)][B][k] == 0) { m[i-(B-j)][B][k] =1; flag=1; } } } if(k<C) { if(C-k>=i) { if( m[0][j][k+i]==0) { m[0][j][k+i]=1; flag=1; } } else { if( m[i-(C-k)][j][C] == 0) { m[i-(C-k)][j][C] =1; flag=1; } } } } if(j) { if(i<A) { if(A-i>=j) { if( m[i+j][0][k]==0) { m[i+j][0][k]=1; flag=1; } } else { if( m[A][j-(A-i)][k] == 0) { m[A][j-(A-i)][k] =1; flag=1; } } } if(k<C) { if(C-k>=j) { if( m[i][0][k+j]==0) { m[i][0][k+j]=1; flag=1; } } else { if( m[i][j-(C-k)][C] == 0) { m[i][j-(C-k)][C] =1; flag=1; } } } } if(k) { if(i<A) { if(A-i>=k) { if( m[i+k][j][0]==0) { m[i+k][j][0]=1; flag=1; } } else { if( m[A][j][k-(A-i)] == 0) { m[A][j][k-(A-i)] =1; flag=1; } } } if(j<B) { if(B-j>=k) { if( m[i][j+k][0]==0) { m[i][j+k][0]=1; flag=1; } } else { if( m[i][B][k-(B-j)] == 0) { m[i][B][k-(B-j)] =1; flag=1; } } } } } } } { FILE* out=fopen("milk3.out", "w"); for(i=0;i<21;i++) { if(poss[i]) { fprintf(out,"%d",i); i++; break; } } for(;i<21;i++) { if(poss[i]) { fprintf(out, " %d", i); } } fprintf(out,"\n"); } return 0; }
Daniel Jasper from Germany writes:
Both other solutions (recursive and non-recursive) use a 3D-array to store the states, so that the memory usage is O(N3). However a 2D Array and O(N2) would be enough since a state is uniquely defined by the amount of milk in bucket B and C. The amount of milk in bucket A is size-of-C minus amount-in-C minus amount-in-B. This solution works with it, and is a little bit shorter (though not more elegant):
#include <stdio.h> int A, B, C; int CB[21][21]; // All states void readFile() { FILE *f; f = fopen("milk3.in", "r"); fscanf(f, "%d%d%d", &A, &B, &C); fclose(f); } void writeFile() { FILE *f; int i; f = fopen("milk3.out", "w"); for(i = 0; i <= C; i++) { if(CB[i][C - i] == 1) { if((i != C-B) && (i != 0)) fprintf(f, " "); fprintf(f, "%d", i); } } fprintf(f, "\n"); fclose(f); } // do brute-force search, c/b: current state void search(int c, int b) { int a; if(CB[c][b] == 1) return; // already searched CB[c][b] = 1; a = C-b-c; // calc amount in A // do all moves: // c->b if(B < c+b) search(c - (B - b), B); else search(0, c + b); // b->c if(C < c+b) search(C, b - (C - c)); else search(c + b, 0); // c->a if(A < c+a) search(c - (A - a), b); else search(0, b); // a->c if(C < c+a) search(C, b); else search(c + a, b); // b->a if(A < b+a) search(c, b - (A - a)); else search(c, 0); // a->b if(B < b+a) search(c, B); else search(c, b + a); } int main () { readFile(); search(C, 0); writeFile(); return 0; }