题目
非常可乐
*Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 44748 Accepted Submission(s): 17595
*Problem Description
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。
Input
三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。
Output
如果能平分的话请输出最少要倒的次数,否则输出"NO"。
Sample Input
7 4 3 4 1 3 0 0 0
Sample Output
NO 3
Author
seeyou
Source
思路 BFS
与这篇文章中的题类似,思路还是BFS,下面代码中我把push动作当成一个函数,来处理这样写BFS更容易理解。
Code
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int siz[3], d[110][110][110];
struct tuples {
int a[3];
};
int ans;
// push from i to j
tuples push(tuples t, int i, int j) {
tuples res = t;
if (t.a[i] > siz[j] - t.a[j]) {
res.a[i] -= (siz[j] - res.a[j]), res.a[j] = siz[j];
} else {
res.a[j] += res.a[i], res.a[i] = 0;
}
return res;
}
bool full(tuples a, int i) {
return a.a[i] == siz[i];
}
bool check(tuples a) {
int cnt = 0;
for (int i = 0; i <= 2; i ++) {
if (a.a[i] == siz[0] / 2)
cnt ++;
}
return cnt == 2;
}
bool bfs() {
queue<tuples> q1;
tuples start;
start.a[0] = siz[0], start.a[1] = 0, start.a[2] = 0;
memset(d, -1, sizeof d);
d[siz[0]][0][0] = 0;
q1.push(start);
while (q1.size()) {
tuples t = q1.front(); q1.pop();
if (check(t)) {
cout << d[t.a[0]][t.a[1]][t.a[2]] << endl;
return true;
}
for (int i = 0; i <= 2; i ++) {
for (int j = 0; j <= 2; j ++) {
if (i == j) continue;
if (t.a[i] && !full(t, j)) {
tuples res = push(t, i, j);
if (d[res.a[0]][res.a[1]][res.a[2]] == -1) {
d[res.a[0]][res.a[1]][res.a[2]] = d[t.a[0]][t.a[1]][t.a[2]] + 1;
q1.push(res);
}
}
}
}
}
return false;
}
int main() {
while(cin >> siz[0] >> siz[1] >> siz[2] && siz[0] && siz[1] && siz[2]) {
if (siz[0] % 2 != 0) {
cout << "NO" << endl;
} else {
bool check = bfs();
if (!check) cout << "NO" << endl;
}
}
}
// 1
/*
7 4 3
4 1 3
3
1 2
1
三次
*