非常可乐(三个杯子倒水问题)

题目描述
红红是个肥宅,所以他很爱喝肥宅快乐水。但是每次当红红买了肥宅快乐水后,左左都要求和红红一起分享这一瓶可乐,而且要和红红喝得一样多。但是红红手中只有两个杯子,他们的容量的分别是 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;
}


  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值