ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HDU 1495 非常可乐

2020-12-05 17:36:47  阅读:334  来源: 互联网

标签:容器 HDU movem moven int pour 1495 now 可乐


题目如下:

蕊蕊和翔翔合资买了一瓶肥宅快乐水儿,他们一共有两个杯子,加上可乐瓶一共有3个可以盛水的容器,并且两个杯子的容积的和等于可乐瓶的容积。蕊蕊和翔翔都不肯让对方喝到更多的肥宅快乐水儿。那么问题来了,在杯子和可乐瓶都没有刻度的情况下,是否有办法可以平分这瓶肥宅快乐水儿?

由于没有刻度,你只能进行两种操作,可以将一个容器中的可乐全部倒入另一个容器中,或者可以将一个容器中的可乐倒入另一个容器使其装满。

当某两个容器中的可乐都等于原可乐瓶容积的一半时,则认为此时可以平分。


Input

输入有多组数据。

每组数据三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。


Output

如果能平分的话请输出最少要倒的次数,否则输出"NO"。


Sample Input

7 4 3

4 1 3

0 0 0


Sample Output

NO

3


解题思路:

这道题跟POJ 3414这道题差不多,我们可以将三个容器之间相互倒可乐看成是遍历的六个方向(具体看代码)。并且在这道题中S如果为奇数,就直接输出NO。(因为S为奇数的话则不能进行平分!)并且,这道题中三个容器之间都可以互相倒可乐,所以我们需要开一个三维数组来记录一下各个容器当中水的状态。(例如:S容器为7,N容器为4,M容器为3的话,那么点就为(7,4,3)。如果这个点没有访问过则将这个点设置为yes并添加到队列中,否则就继续搜索其它状态)由于这道题还需要输出最少的操作次数,因此这道题我们采用bfs记忆化搜索。(详情参考POH 3414 这道题的笔记,这里就不再过多讲解!)


POJ 3414 笔记如下: https://www.cnblogs.com/gao79135/p/14088520.html


在这道题中,由于S的大小在(0,101)之间,因此S的下标为1-100,且由于N+M==100,所以N和M容器的下标都为1-99。所以我们设置访问数组的大小为:status[104][104][104],并且队列的大小也应该在100x100x100之下。(因为实际遍历的状态中远小于这个数)。


代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct Point
{
	int Swater;               //S可乐的容量
	int Nwater;               //N可乐的容量
	int Mwater;               //M可乐的容量
	int pre;                  //定义当前状态中之前的状态在队列中的下标。
} Q[250000];                  
bool status[104][104][104];     //代表标记该状态是否被访问过的数组
int Count = 0;                //定义最少倒的次数
int S, N, M;                  //代表可乐的体积,两个杯子的容量
int flag = 0;
struct Point bfs();           //代表进行bfs的函数
void dfs(struct Point end_point);                   //代表进行递归的函数(这里用dfs表示)
void init();                                        //代表进行初始化的函数

void init()
{
	int i, j, k;
	for (i = 0; i < 104; i++)
	{
		for (j = 0; j < 104; j++)
		{
			for (k = 0; k < 104; k++)
			{
				status[i][j][k] = false;
			}
		}
	}
}

struct Point bfs()
{
	int moves, moven, movem;  //代表移动之后的容器状态
	int i, now=0, front=1; 
	int mid = S / 2;
	Q[0].Swater = S;          //定义刚开始的状态
	Q[0].Mwater = 0;
	Q[0].Nwater = 0;
	Q[0].pre = -1;
	status[S][0][0] = true;   //代表起点已经访问过
	while (true)
	{
		if (now > front)
		{
			break;
		}
		for (i = 0; i < 6; i++)
		{
			moves = Q[now].Swater;
			moven = Q[now].Nwater;
			movem = Q[now].Mwater;
			if (i == 0)         //代表将S容器的水倒入N容器
			{
				int pour = min(moves, N - moven);
				moves -= pour;
				moven += pour;
				if (pour == 0)  //如果N容器的水已满,代表S容器的水无法倒入N容器,结果为状态跟之前一样没有改变,所以需要进行返回
				{
					continue;
				}
			}
			else if (i == 1)   //代表将S容器的水倒入M容器
			{
				int pour = min(moves, M - movem);
				moves -= pour;
				movem += pour;
				if (pour == 0)
				{
					continue;
				}
			}
			else if (i == 2)  //代表将N容器的水倒入S容器
			{
				int pour = min(moven, S - moves);
				moven -= pour;
				moves += pour;
				if (pour == 0)
				{
					continue;
				}
			}
			else if (i == 3) //代表将N容器的水倒入M容器
			{
				int pour = min(moven, M - movem);
				moven -= pour;
				movem += pour;
				if (pour == 0)
				{
					continue;
				}
			}
			else if (i == 4) //代表将M容器的水倒入S容器
			{
				int pour = min(movem, S - moves);
				movem -= pour;
				moves += pour;
				if (pour == 0)
				{
					continue;
				}
			}
			else if (i == 5) //代表将M容器的水倒入N容器
			{
				int pour = min(movem, N - moven);
				movem -= pour;
				moven += pour;
				if (pour == 0)
				{
					continue;
				}
			}
			if (status[moves][moven][movem] == false)  //如果该状态还没有访问过
			{
				front++;
				Q[front].Swater = moves;
				Q[front].Nwater = moven;
				Q[front].Mwater = movem;
				Q[front].pre = now;
				status[moves][moven][movem] = true;   //代表该状态已经访问过了
			}
		}
		if ((Q[now].Swater == mid && Q[now].Nwater == mid) || (Q[now].Swater == mid && Q[now].Mwater == mid) || (Q[now].Nwater == mid && Q[now].Mwater == mid))
		{
			return Q[now];                        //返回当前状态
		}
		now++;
	}
	struct Point bad;
	bad.pre = -10000;
	return bad;
}

void dfs(struct Point end_point)
{
	if (end_point.pre == -10000)
	{
		cout << "NO" << endl;
		flag = 1;
		return;
	}
	if (end_point.pre != -1)
	{
		Count++;
	}
	if (end_point.pre == -1)
	{
		return;
	}
	dfs(Q[end_point.pre]);                        //代表从当前状态递归到该状态之前的状态
}

int main()
{
	struct Point end_point;
	while (scanf("%d %d %d", &S, &N, &M) != EOF)
	{
		init();
		if (S == 0 && N == 0 && M == 0)
		{
			return 0;
		}
		else
		{
			if (S % 2 == 0)
			{
				end_point = bfs();
				dfs(end_point);
				if (flag == 0)
				{
					cout << Count << endl;
				}
			}
			else
			{
				cout << "NO" << endl;
			}
		}
		Count = 0;
		flag = 0;
	}
}

标签:容器,HDU,movem,moven,int,pour,1495,now,可乐
来源: https://www.cnblogs.com/gao79135/p/14090331.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有