nyoj21 三个水杯倒水

本文介绍了一种使用广度优先搜索(BFS)解决三个水杯倒水,以达到特定水量组合的最少操作次数问题。在搜索过程中,通过结构体保存每个状态的水量和倒水次数,并避免重复状态,确保不超过水杯容量。同时提到,该问题也可通过深度优先搜索(DFS)来解决,每次达到目标状态时更新最小步数。
摘要由CSDN通过智能技术生成

看到用最少次数就会想到要用bfs,那么主要就是搜索过程中的处理:对于三个杯子我们标记为0,1,2...我们总共有以下6种情况的倒水情况:


那么,对于杯子先有的一种状态,对于每一种状态,我们用一个结构体来保存,里面包括当前三个杯子的水量,最开始的状况到现在状况倒水的次数step,那么在此状态下,我们就对六种情况判断,能不能这样倒水,能就入队列,能倒水的判断我们要不出现以前倒水过程中出现过得状态,不超过水杯容量、、、、、等

下面是我的详细代码注释(对于此题,还可以用dfs,每次达到要求状态就更新一下步数让其最小)

//  时间12  内存1436 
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

int six[6][2]={{0,1},{0,2},{1,0},{1,2},{2,0},{2,1}};//六种倒水的方法
bool flag[105][105][105];//看是否出现过

struct cup//杯子的状态
{
	int a[3];
	int step;
}CUP,start,end;//这里的start和end就是用来存放开始输入的杯子,和最终状态的

int del(cup &cc,int x,int y)//将cc的状态改变,从x倒水到y中
{
	if(cc.a[x]!=0 || cc.a[y]!=start.a[y])//不出现这两情况:没水可倒,或者b水杯现在有的水就是我们最开始输入的水杯大小,意思就是满了...
	{
		if(cc.a[x]+cc.a[y]<=start.a[y])//吧x中全部倒入y中都不大于y杯子的大小
		{
			cc.a[y]+=cc.a[x];
			cc.a[x]=0;//x倒完
		}
		else
		{
			cc.a[x]-=(start.a[y]-cc.a[y]);//首先这种情况是不能把y倒满,那么x就会倒掉(start.a[y]-cc.a[y]),这个差就是y由现在到满所需的水
			cc.a[y]=start.a[y];//y倒满,注意一定不要和上面的式子弄反,否则y先改变,x的剩余也会不正确
		}
		if(!flag[cc.a[0]][cc.a[1]][cc.a[2]])//这种状态没有到过
		{
			flag[cc.a[0]][cc.a[1]][cc.a[2]]=true;
			return 1;
		}
	}
	return 0;
}

int bfs()
{
	cup CUP;//
	CUP.a[0]=start.a[0];
	CUP.a[1]=CUP.a[2]=CUP.step=0;//初始化状态,注意别CUP=start,因为我们这个状态是只有最大的杯子是满的,其他为0
	queue<cup>q;
	q.push(CUP);
	flag[CUP.a[0]][CUP.a[0]][CUP.a[2]]=true;
	
	while(!q.empty())
	{
		cup pre=q.front();
		q.pop();
		if(pre.a[0]==end.a[0] && pre.a[1]==end.a[1] && pre.a[2]==end.a[2])
			return pre.step;
		for(int i=0;i<6;i++)
		{
			cup p=pre;//用一个临时变量
			if(del(p,six[i][0],six[i][1]))//处理看能否倒水,能就操作,并且保留操作后的状态,入队
			{
				p.step=pre.step+1;
				//printf("%d %d %d %d\n",p.a[0],p.a[1],p.a[2],p.step);
				q.push(p);
			}
		}
	}
	return -1;
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		memset(flag,false,sizeof(flag));
		scanf("%d%d%d",&start.a[0],&start.a[1],&start.a[2]);
		scanf("%d%d%d",&end.a[0],&end.a[1],&end.a[2]);
		printf("%d\n",bfs());
	}
	return 0;
}
dfs  改正的在下面

#include<stdio.h>
#include<string.h>

struct cup
{
	int a[4];
	int step;
}start,end;

bool flag[105][105][105];
int ans;
int vis[6][2]={{1,2},{1,3},{2,1},{2,3},{3,1},{3,2}};

bool del(cup & c,int x,int y)
{
	if(c.a[x]==0 || c.a[y]==start.a[y])
		return false;
	if(c.a[x]+c.a[y]>start.a[y])
	{
		c.a[x]-=(start.a[y]-c.a[y]);
		c.a[y]=start.a[y];
	}
	else
	{
		c.a[y]+=c.a[x];
		c.a[x]=0;
	}
	if(flag[c.a[1]][c.a[2]][c.a[3]])
		return false;
	return true;
}

void dfs(cup CUP)
{
	if(CUP.a[1]==end.a[1] && CUP.a[2]==end.a[2] && CUP.a[3]==end.a[3])
	{
		if(CUP.step<ans)//这里搜索到就与ans(也就是我们的答案比较一下..取小的)
			ans=CUP.step;
		return;
	}
	for(int i=0;i<6;i++)
	{
		cup c;c.a[1]=CUP.a[1];c.a[2]=CUP.a[2];c.a[3]=CUP.a[3];
		if(del(c,vis[i][0],vis[i][1]))
		{
			flag[c.a[1]][c.a[2]][c.a[3]]=true;
			c.step=CUP.step+1;
			dfs(c);
			flag[c.a[1]][c.a[2]][c.a[3]]=false;
		}
	}
	return ;
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		ans=10000;
		memset(flag,false,sizeof(flag));
		scanf("%d%d%d",&start.a[1],&start.a[2],&start.a[3]);
		scanf("%d%d%d",&end.a[1],&end.a[2],&end.a[3]);

		flag[start.a[1]][0][0]=true;
		cup p;p.a[1]=start.a[1];p.a[2]=p.a[3]=p.step=0;
		dfs(p);
		if(ans<100)
		   printf("%d\n",ans);
		else 
			printf("-1\n");
	}
	return 0;
}
个人愚昧观点...欢迎指正与讨论


评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值