题目描述
红红是个肥宅,所以他很爱喝肥宅快乐水。但是每次当红红买了肥宅快乐水后,左左都要求和红红一起分享这一瓶可乐,而且要和红红喝得一样多。但是红红手中只有两个杯子,他们的容量的分别是 N 毫升 和 M毫升,可乐的体积为 S 毫升(正好装满一升)。他们三个之间可以相互倒可乐,都是没有刻度的,而且 S == N+M,0 < S < 101 0 < N 0 < M。聪明的你们能告诉他们能平分吗,如果能请输出倒可乐的最少次数,如果不能输出”NO“。
输入
三个整数: S 可乐的体积, N 和 M 是两个杯子的容量,以 ”0 0 0”结束。
输出
如果能输出倒可乐的最少次数,如果不能输出“NO”。
样例输入
7 4 3
4 1 3
0 0 0
样例输出
NO
3
每步都有注释,可自行理解。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 105;
bool v[4];
bool vis[maxn][maxn][maxn];
struct Node//表示每次倒水后的步数,step是记录倒水后的步数
{
int v[4];//可以用来标记每一个状态的水位情况
int step;//步数
} temp;
void pour(int a, int b) //倒水函数,把a杯子中的可乐倒到b杯子//表示每次倒水后的状态。
{
int sum = temp.v[a] + temp.v[b];//可乐总量是sum,并且sum=a+b;
if (sum >= v[b])//如果总数大于sum>b;
temp.v[b] = v[b];//就将 b装满。
else
temp.v[b] = sum;//如果总数sum小于b的容量就将所有的可乐全部放入b中。
temp.v[a] = sum - temp.v[b];//剩下a中的可乐就是sum-b中的。
}
void BFS()
{
queue<Node>q;//申请一队列
Node now;//表示现在的水量
now.v[0] = v[0];//结构体数组的初始化 总的水量
now.v[1] = 0;//结构体数字的初始化 第一个杯子水量为零
now.v[2] = 0;//结构体数组的初始化 第二个杯子的水量为零
now.step = 0;//将初始的步数设置为零
q.push(now);//将现在的状态水量入队
memset(vis, 0, sizeof(vis));//将数组初始化为0;
vis[v[0]][0][0] = true;//将vis数组标记为1;
while (!q.empty())//如果队列不为空,执行以下的操作。
{
now = q.front();//取队列头元素 ,也就是说当前的每个杯子的水量就是队头的元素
q.pop();//取出后,就将队列的第一个元素出队
if (now.v[0] == now.v[2] && now.v[1] == 0)//如果第一个杯子的水等于第二个杯子的水就输出步数。
{
cout << now.step << endl; //步骤输出
return;//输出后就直接return 出函数即可。
}
for (int i = 0; i < 3; i++)//查看每一种的情况
{
for (int j = 0; j < 3; j++)
{
if (i != j)//自己不倒水给自己
{
temp = now;
//每个水位情况都要把所有操作枚举一遍,
//所以都要赋值为原始水位情况
pour(i, j);//每经过一个过程就将执行一次倒水函数。
if (!vis[temp.v[0]][temp.v[1]][temp.v[2]])//如果本次状态没有经历过,也就是说本次状态的数组值为零。
{
temp.step++;//记录每次倒水后步数加一
q.push(temp);//将当前的状态入队
vis[temp.v[0]][temp.v[1]][temp.v[2]] = true;//并且将此次状态标记为1;
}
}
}
}
}
cout << "NO" << endl;// 不能平分输出NO。
}
int main()
{
while (scanf("%d%d%d", &v[0], &v[1], &v[2]) != EOF)
{
if (v[0] + v[1] + v[2] == 0)//如果都没有水直接结束。//排除有负数的情况。
break;
if (v[1] > v[2]) //保证v1小于v2也就是杯子a<b杯子
swap(v[1], v[2]);否则交换两个杯子
BFS();//执行广度搜索BFS
}
return 0;
}