农夫约翰有三个容量分别为 A , B , C A,B,C A,B,C 升的挤奶桶。
最开始桶 A A A 和桶 B B B 都是空的,而桶 C C C 里装满了牛奶。
有时,约翰会将牛奶从一个桶倒到另一个桶中,直到被倒入牛奶的桶满了或者倒出牛奶的桶空了为止。
这一过程中间不能有任何停顿,并且不会有任何牛奶的浪费。
请你编写一个程序判断,当 A A A 桶是空的时候, C C C 桶中可能包含多少升牛奶,找出所有的可能情况。
输入格式
共一行,包含三个整数
A
,
B
,
C
A,B,C
A,B,C。
输出格式
共一行,包含若干个整数,表示
C
C
C 桶中牛奶存量的所有可能情况,请将这些数字按升序排列。
数据范围
1
≤
A
,
B
,
C
≤
20
1≤A,B,C≤20
1≤A,B,C≤20
输入样例1:
8 9 10
输出样例1:
1 2 8 9 10
输入样例2:
2 5 10
输出样例2:
5 6 7 8 9 10
这题肯定是要搜遍所有的情况的,要考虑到如何记录每一层的状态和怎么标记每一层哪些状态搜过。每次搜的时候搜遍所有的桶倒向所有的桶,双重循环就可以解决这个问题。
如果i倒向j,对于每次应该倒多少:
- 如果 i i i 能够全部倒进 j j j 且 j j j 不会溢出,那么就倒i所有的量
- 如果 i i i 不能够全部倒进 j j j,那么就倒入 j 桶的容量减去 j 当前的量
#include<iostream>
#include<queue>
using namespace std;
const int N = 25;
struct Node { //定义结构体,用来在BFS中存状态
int a, b, c; //a,b,c分别表示各个桶的牛奶量
};
int A, B, C; //存容量
bool st[N][N][N]; //三维数组标记状态
void bfs() {
queue<Node>q;
q.push({0,0,C});//压入初始状态
st[0][0][C] = 1;//标记上初始状态
int contain[3] = { A,B,C }; //用数组存最大容量,便于之后遍历
while (q.size()) {
auto t = q.front();
q.pop();
for (int i = 0; i < 3; i++) { //枚举每个桶倒向每个桶
for (int j = 0; j < 3; j++) {
if (i != j) {//不能倒向自己
//i往j倒,要不i倒完,倒w[i],要不j倒满,倒contain[j] - w[j]
int w[3] = { t.a,t.b,t.c }; //定义数组为当前状态的每个桶的牛奶量,便于搜索
//找出倒出的量
int pour = min(w[i], contain[j] - w[j]);
w[i] -= pour, w[j] += pour;
if (!st[w[0]][w[1]][w[2]]) { //如果这个状态没有标记过
st[w[0]][w[1]][w[2]] = 1;
q.push({w[0],w[1],w[2]});
}
}
}
}
}
}
int main() {
cin >> A >> B >> C;
bfs();
for (int i = 0; i <= C; i++) { //直接枚举每一种容量,找出A桶是0且标记过的状态
for (int j = 0; j <= B; j++) {
if (st[0][j][i])cout << i << " ";
}
}
return 0;
}