非常可乐HDU1495

本文介绍了一道经典搜索题目HDU1495的解题思路及BFS实现过程,通过将三个杯子的水量作为状态,并定义六种状态转移方式,实现了水量的平衡分配。

传送门:HDU1495

中文题意就不说了。

思路:这题被挂到搜索专题里,可我怎么想也想不出来该咋搜,其实还是思路太窄,原来做的搜索题大部分都是走迷宫什么的。。思路被限制住了,但看了题解发现这里bfs的状态转移实际上并不难,在走迷宫之类的问题中,每个点都是一种状态,状态都是从一个点朝四个方向进行转移,这里三个杯子的水量是一种状态,只不过状态转移换成了把水从哪个杯子倒向哪个杯子的问题,一共有六种情况S->N  N->S  S->M   M->S  M->N   N->M,只要每次bfs取出一种状态来,进行这六种状态转移,再放入队列就好了,还有要注意的一点是标记数组开二维就够了,分别N和M两个杯子中的水量,当然,这里数据量小开三维也无所谓。

PS:为了方便讨论六种情况,最好提前确定N和M哪个是较大的杯子,这里我取N为较大的杯子。

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<map>
#define ll long long
#define pi acos(-1)
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>P;
int s,n,m;
int book[110][110];
struct node{
	int n,m,s;
	int step;
};
//s->n ;s->m ; n->s ; n->m ;m->s ;m->n
void bfs()
{
	memset(book,0,sizeof(book));
	queue<node>q;
	while(!q.empty())
	q.pop();
	q.push({0,0,s,0});
	while(!q.empty())
	{
		node t=q.front(),a;
		a.step=t.step+1;
		q.pop();
		if(t.n==s>>1&&t.s==s>>1)
		{
			printf("%d\n",t.step);
			return ;
		}
		if(t.s+t.n<=n)//s->n
		{
			a.n=t.s+t.n;
			a.s=0;
			a.m=t.m;
			if(!book[a.n][a.m])
			{
				q.push(a);
				book[a.n][a.m]=1;
			}
		}
		else
		{
			a.n=n;
			a.s=t.s+t.n-n;
			a.m=t.m;
			if(!book[a.n][a.m])
			{
				q.push(a);
				book[a.n][a.m]=1;
			}
		}
		if(t.s+t.m<=m)//s->m
		{
			a.m=t.s+t.m;
			a.s=0;
			a.n=t.n;
			if(!book[a.n][a.m])
			{
				q.push(a);
				book[a.n][a.m]=1;
			}
		}
		else
		{
			a.m=m;
			a.s=t.s+t.m-m;
			a.n=t.n;
			if(!book[a.n][a.m])
			{
				q.push(a);
				book[a.n][a.m]=1;
			}
		}
		a.s=t.s+t.n;//n->s
		a.n=0;
		a.m=t.m;
		if(!book[a.n][a.m])
		{
			q.push(a);
			book[a.n][a.m]=1;
		}
		a.s=t.s+t.m;//m->s
		a.m=0;
		a.n=t.n;
		if(!book[a.n][a.m])
		{
			q.push(a);
			book[a.n][a.m]=1;
		}
		if(t.m+t.n<=m)//n->m
		{
			a.m=t.m+t.n;
			a.n=0;
			a.s=t.s;
			if(!book[a.n][a.m])
			{
				q.push(a);
				book[a.n][a.m]=1;
			}
		}
		else
		{
			a.m=m;
			a.n=t.n+t.m-m;
			a.s=t.s;
			if(!book[a.n][a.m])
			{
				q.push(a);
				book[a.n][a.m]=1;
			}
		}
		if(t.m+t.n<=n)//m->n
		{
			a.n=t.m+t.n;
			a.m=0;
			a.s=t.s;
			if(!book[a.n][a.m])
			{
				q.push(a);
				book[a.n][a.m]=1;
			}
		}
		else
		{
			a.n=n;
			a.m=t.n+t.m-n;
			a.s=t.s;
			if(!book[a.n][a.m])
			{
				q.push(a);
				book[a.n][a.m]=1;
			}
		}
	}
	printf("NO\n");
	return ;
}
int main()
{
	while(scanf("%d%d%d",&s,&n,&m)&&s+n+m)
	{
		if(s&1)//奇数肯定无法等分
		{
			printf("NO\n");
			continue;
		}
		if(n<m)
		swap(n,m);
		bfs();
	}
    return 0;
}
六种情况稍微细心一点并不难写。

心得:怪不得某学长说DP和bfs有联系,原来还搞不明白这两者能有啥联系,不过从这个题看来,二者本质都是确定了初始状态和状态转移关系之后,对衍生状态的一种枚举,不过DP的思想更凝练些,而bfs更通俗易懂罢了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值