HDU-1495 (BFS)

总体思路与经典的倒水问题相同(可参考刘汝佳《算法竞赛入门经典》P202-P205对Uva10603的讲解)

对于总可乐量为奇数的情况,直接输出不可能,因为对于没有刻度的整数容量的杯子,我们可以操作的最小可乐量不会小于1,因而无法平分。

下面讨论偶数的情况:

把每种状态以三个杯子中的水量排成的有序三元组表示,该三元组可看成有向图中的一个节点。如果经过一次倾倒,状态A转移成了状态B,那么在图中就有一条从A指向B的边。

我们从图中的(S,0,0)点出发,寻找两个杯子中各有总可乐量的一半的状态,即为搜索的终点。

(其实这一点题目说的有些含糊,因为题目只问了两个人能不能平分,其实平分可乐并不需要两个杯子中各有一半,比如第一组测试数据的4 1 3这种情况,起点是4 0 0,第一步从第一个往第三个倒 得到 1 0 3,第二步从第三个往第二个倒,得到 1 1 2,这样一个人喝第三杯,另一个喝第一第二杯,所以只倒两次就可以,这种理解终点的条件应该是至少有一个杯子中的可乐量时总量的一半,但是根据样例的数据,题目并不是这个意思,所以理解题目还是要靠数据啊23333)

对于这样的图上的最短路问题,我们应该使用BFS。

代码如下(该题还有数论做法,性能上由碾压优势,有兴趣的同学可以去网上学习一下)

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
struct sta
{
	int coke[3];
};
int step[101][101][101], cap[3];
queue<sta> q;
int bfs()
{
	while (!q.empty()) q.pop();
	for (int i = 0; i <= cap[0]; i++)
		for (int j = 0; j <= cap[1]; j++)
			for (int k = 0; k <= cap[2]; k++)
				step[i][j][k] = -1;
	q.push({ {cap[0],0,0} });
	step[cap[0]][0][0] = 0;
	while (!q.empty())
	{
		sta t = q.front(),temp; q.pop();
		for(int i=0;i<3;i++)
			for(int j=0;j<3;j++)
				if (i != j && t.coke[i] > 0 && t.coke[j] < cap[j])
				{
					int dao = min(t.coke[i], cap[j] - t.coke[j]);
                            //要么倒光一杯,要么倒满另一杯,以小的为准
					temp.coke[i] =t.coke[i]- dao;
					temp.coke[j] =t.coke[j]+ dao;
					temp.coke[3 - i - j] = t.coke[3 - i - j];
					if (step[temp.coke[0]][temp.coke[1]][temp.coke[2]]==-1)
					{
						step[temp.coke[0]][temp.coke[1]][temp.coke[2]] = step[t.coke[0]][t.coke[1]][t.coke[2]] + 1;
						if ((temp.coke[0] == cap[0] / 2)+(temp.coke[1] == cap[0] / 2)+(temp.coke[2] == cap[0] / 2)==2)
                //关系式成立为1,不成立为0,意为有两杯,每杯占总量一半
							return step[temp.coke[0]][temp.coke[1]][temp.coke[2]];
						q.push(temp);
					}
				}
	}
	return 0;
}
int main()
{
	while (cin >> cap[0] >> cap[1] >> cap[2] && cap[0])
	{
		if (cap[0] & 1)
		{
			cout << "NO"<<endl;
			continue;
		}
		int t = bfs();
		if (t) cout << t << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

最后还有几点想说的:

1. 不要滥用memset

在初始step数组时,我开始写的是

#include<cstring>
memset(step,-1,sizeof(step));

但是这样会使速度变慢,因为为了满足数据大小的要求,step数组开的很大,但是对于很多组数据来说,他们只用到了一小部分,而这条语句每次都把这个巨大的数组操作一通,自然就慢了

2. HDU 的C++和G++,性能差异很大,而且哪个快不好说。。。

3.不要滥用memcpy

memcpy(&temp,&t,sizeof(sta));

对于int[3] 这种比较小的结构体,还没三个变量挨个赋值快

三次优化效果,可见1和3的提升还是很大的

《HDU-1495 (BFS)》

    原文作者:BFS
    原文地址: https://blog.csdn.net/Accsc/article/details/81541487
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞