题意:有3个有一定容量的杯子,给定一个水的量。问是否能让一个杯子装这个给定容量的水,以及所需要倒来倒去的水的最小量。如果不能,则能倒出的比给定容量小但最接近的量,以及所需要进行倒的水的最小量。
思路:虽然是隐式图搜索的问题,其实和之前数据结构基础章节的图的题很类似,就是一个状态转换,然后深搜或宽搜。只不过这里状态的变换不是像之前那样是固定的,可以用一个多维数组来表示;这里的变换是倒水后三个杯子的容量变化。其实题目中也明确给出了状态的变化,要么某水杯倒完,要么另一水杯被装满。比如a倒向b,可以像下面这样写:
//a to b
if(hd.sa>0)
{
int cha=b-hd.sb;
if(hd.sa>=cha) newhd={hd.sa-cha,b,hd.sc};
else newhd={0,hd.sb+hd.sa,hd.sc};
}
if(vis[newhd.sa][newhd.sb]==0)
{
queue[rear++]=newhd;
}
但是之后a倒向c等等,与此类似,但又需要重新写一个类似的代码而不能重用这段代码。要重用的话,用一个数组来表示结构体的sa、sb、sc。
这样用数组来表示其成员的方法在之前数据结构基础图相关的题中就已经见过,比如迷宫的四个方向等。
但是写完之后通过了网上能找到的所有测试数据,还是WA。。卡了太长时间。最后,这里有所帮助。主要是考虑到两个相同的状态,可能后来出现的状态的倒水量比已经出现过该状态时的倒水量要小,这样的话,虽然该状态已出现过,还是需要把该状态加入队列进行扩展;否则你找到的就不是最小的倒水量。网上大部分的题解应该都是WA了,此题应该后来加强了数据。。因为要找的是最小的到水量,重复状态的处理是一个方面,还有一个方面是bfs进行遍历时找到目标值后并不能终止,因为bfs找的是最少次数的,并不一定是最小倒水量的,必须把所有结点扩展完。
综上,需要注意的点如下:
1.bfs或dfs需要遍历完所有结点,不能提前跳出。
2.重复状态出现时,需要比较两者的倒水量。如果后者的倒水量较小,还是需要重新访问。(有的用hash判重貌似可以;紫书上记录所有解,结束后再找最优解,当然就不存在这个问题了。。)
后面附上一些数据,但是没有检测出第二个注意项。。
Code:
#include<