题目描述
农民约翰有三个容量分别是A,B,C升的桶,A,B,C分别是三个从1到20的整数,最初,A和B桶都是空的,而C桶是装满牛奶的。有时,约翰把牛奶从一个桶倒到另一个桶中,直到被灌桶装满或原桶空了。当然每一次灌注都是完全的。由于节约,牛奶不会有丢失。 写一个程序去帮助约翰找出当A桶是空的时候,C桶中牛奶所剩量的所有可能性。
Input
单独的一行包括三个整数A,B和C。
Output
只有一行,列出当A桶是空的时候,C桶牛奶所剩量的所有可能性。
Sample Input
8 9 10
Sample Output
1 2 8 9 10
倒水总共6种状态,分别为
- A->B
- B->A
- A->C
- C->A
- B->C
- C->B
记杯子i容量为 vi v i ,杯子内所含水为 wi w i ;
所以我们记录每一次 A A ,, C C 的(其实只需要记录2个杯子即可,任意2个杯子 w w 确定了那么第3个杯子的),然后对以上6种情况进行遍历,如果碰见当前 w0,w1,w2 w 0 , w 1 , w 2 的组合未被标记,则以当前 w0,w1,w2 w 0 , w 1 , w 2 标记并以其为起点进行深搜,这样就能求出任意两个杯子相互倒水的所有情况了。然后取 w0=0 w 0 = 0 的时候 w2 w 2 的值即可
AC代码如下
#include <map>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <iostream>
#include <algorithm>
#define fori(a) for(int i=0;i<a;i++)
#define forj(a) for(int j=0;j<a;j++)
#define ifor(a) for(int i=1;i<=a;i++)
#define jfor(a) for(int j=1;j<=a;j++)
#define IO do{\
ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);}while(0)
#define mp(a,b) make_pair(a,b)
using namespace std;
typedef long long ll;
const int maxn = 210;
map <pair<int,int>,bool>q; //标记三个杯子中的当前容量是否已经遍历过,避免重复搜索
pair <int,int >buf;
map <int,bool>res;
int cnt;
int ans[maxn];
int dir[6][2]= {{0,2},{0,2},{1,2},{1,0},{2,0},{2,1}};//从dir[i][0]往dir[i][1]中倒水
int v[3]; //每个杯子的容量
int w[3]; //每个杯子已经装了多少水
int push(int a,int b) {return min(w[a],v[b]-w[b]);} //a向b中倒水的量
void dfs() {
if(w[0]==0&&!res[w[2]]) { //如果A为0且C中的容量未被记录
ans[cnt++] = w[2];
res[w[2]] = true;
}
fori(6) {
int val = push(dir[i][0],dir[i][1]);
if(val) {
//倒水操作
int a = dir[i][0];
int b = dir[i][1];
w[a] -= val;
w[b] += val;
//*********//
buf = mp(w[0],w[1]);
if(!q[buf]) { //如果这个结果未曾被遍历,则进入,继续dfs
q[buf] = true;
dfs();
}
w[a] += val;
w[b] -= val;
}
}
}
int main() {
fori(3)
cin >> v[i];
w[2] = v[2];
dfs();
sort(ans,ans+cnt);
fori(cnt){
if(i)
cout <<" ";
cout << ans[i];
}
cout << endl;
return 0;
}