题目
题目描述
有三个牛奶桶,三个桶的容积分别是A,B,C
,最小为1,最大为20。刚开始只有第三个桶里面装满了牛奶,其余两个桶都是空的。我们现在可以将第三个桶中的牛奶往其他两个桶里面倒一些牛奶,然后还可以将其他两个桶往另一个桶中倒牛奶,但是我们在操作的时候有严格的要求:
从一个桶往另一个桶中倒牛奶,要么直到第二个桶已经装满了,要么直到第一个桶已经空了。在倒牛奶的过程中不允许浪费。
在来回经过一系列的倒牛奶的操作之后,现在我们需要知道当第一个牛奶桶为空的时候,第三个牛奶桶可能的牛奶量为多少。
输入
一行输入三个整数 A,B,C。
输出
按照从小到大的顺序输出当第一个桶为空时第三个桶中的可能牛奶量。
输入样例
8 9 10
输出样例
1 2 8 9 10
输入样例
2 5 10
输出样例
5 6 7 8 9 10
题目分析
最开始拿到这个题目的时候想过用枚举的方法来实现,但是在如何处理状态的地方卡住了,不知道怎样才能停止。基础还是不扎实啊,思维不够。
用暴力枚举来求解这个题目,因为每个桶的状态最多为20,那么最多的状态为20*20*20=8000
,这个数据量不算大,所以我们可以用一个三维的布尔类型状态数组来记录。states[a][b][c]
表示三个桶的牛奶分别为a,b,c
时的状态。状态是通过倒牛奶的操作来实现的,只有6种操作来转移状态:
A->B A->C B->A B->C C->A C->B
,我们只要将这六种操作模拟出来就行了。
代码
/*
ID: yinzong2
PROG: milk3
LANG: C++11
*/
#define MARK
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 21;
int A,B,C;
int states[maxn][maxn][maxn];
void solve(int a, int b, int c);
void next(int x, int y, int z) {
if (!states[x][y][z]) {
states[x][y][z] = true;
solve(x, y, z);
}
}
// 枚举所有的可能状态,如果某个状态已经到达过,那么就不需要处理它
void solve(int a, int b, int c) {
int x, y, z;
// A->B
x = 0; y = a+b; z = c;
if (y > B) {
x = y-B;
y = B;
}
next(x, y, z);
// A->C;
x = 0; y = b; z = a+c;
if (z > C) {
x = z-C;
z = C;
}
next(x, y, z);
// B->A
x = a+b; y = 0; z = c;
if (x > A) {
y = x-A;
x = A;
}
next(x, y, z);
// B->C
x = a; y = 0; z = b+c;
if (z > C) {
y = z-C;
z = C;
}
next(x, y, z);
// C->A
x = a+c; y = b; z = 0;
if (x > A) {
z = x-A;
x = A;
}
next(x, y, z);
// C->B
x = a; y = b+c; z = 0;
if (y > B) {
z = y-B;
y = B;
}
next(x, y, z);
}
int main() {
#ifdef MARK
freopen("milk3.in", "r", stdin);
freopen("milk3.out", "w", stdout);
#endif // MARK
while (cin >> A >> B >> C) {
memset(states, false, sizeof(states));
states[0][0][C] = true;
solve(0, 0, C);
bool first = true;
for (int c = 0; c <= C; ++c) {
if (states[0][C-c][c]) {
if (!first) cout << " ";
cout << c;
first = false;
}
}
cout << endl;
}
return 0;
}