bfs-倒水问题

题意:
倒水问题 “fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。现有A,B容量的杯子和饮水机,通过有限步骤的倒水,得到容量为c的水。
输入:
输入包含多组数据。每组数据输入 A, B, C 数据范围 0 < A <= B 、C <= B <=1000 、A和B互质
输出:
你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。
思路:
分析这道题的初始状态是A,B中的会都是0,现要得到c容量的水即A或者B杯子中有一个杯子中的水的容量是c即可。中间有限次步骤可以是fill A,fill B,empty A,empty B,pour A B,pour B A,这样每次中间杯子中的状态值都是以上步骤导致的,所以把A,B中的容量(x,y)作为状态点,从初始(0,0)到最终状态点(0,y)或者(x,0),这时就可以用bfs进行广搜,中间状态通过对(x,y)进行六种步骤中未进行过的一个生成状态。特判就是x等于0或者是y等于0,然后对六种步骤的每一个求出一个(x,y),如果(x,y)未进行过(没有被标记),就选择放入队列,直到队列为空或者到达最终状态。
总结:
这是隐式图问题,利用bfs做,主要难点是找出中间节点(状态),题目中隐式给出了每一种可走的方案,要根据可走的方案得出每一个可行的中间状态(点)。
代码:

/*
对于状态值status
可以用map来记录每个状态点的前驱(用来输出路径)  map<status,status>
map也可以用来标记是否到过   map<status,bool>
开始状态0,0    容量A,B,C     结束状态A杯子中=c||B杯子中=c
*/
#include<iostream>
#include<map>
#include<queue>
#include<string>
using namespace std;
int A,B,C;
struct point
{
	int x,y;
	point(){}
	point(int _x,int _y)
	{
		x=_x;y=_y;
	}
    bool operator<(const point &a)const 
	{
        return x == a.x ? y < a.y : x < a.x;
    }

    bool operator==(const point &a)const
	{
        return x == a.x && y == a.y;
    }
	point ATOB() 
	{
		point c;c.x=max(x+y-B,0);c.y=min(B,x+y);return c;
	}
	point BTOA()
	{
		point c;c.x=min(A,x+y);c.y=max(0,x+y-A); return c;
	}
	point FILLA()
	{
		return point(A,y);
	}
	point FILLB()
	{
		return point(x,B);
	}
	point EMPTYA()
	{
		return point(0,y);
	}
	point EMPTYB()
	{return point(x,0);
	}
};
map<point,bool> flag;
map<point,point>path;
map<point,string>ppath;
queue<point> q;
void turn(point x,point y,string str)
{
	if(!flag[y])
	{  
		flag[y]=1;path[y]=x;ppath[y]=str;q.push(y);
	}
}
void print(point ed)
{ 
 if(ed.x==0&&ed.y==0) return;
	print(path[ed]);
	cout<<ppath[ed]<<endl;
}
void bfs(int x,int y)
{
	point source(x,y);q.push(source); flag[source]=1;
	while(!q.empty())
	{    
		point now=q.front();q.pop();
		if(now.x==C||now.y==C) 
		{  
			print(now);return;
		}   
		turn(now,now.ATOB(),"pour A B");
		turn(now,now.BTOA(),"pour B A");
		turn(now,now.FILLA(),"fill A");
		turn(now,now.FILLB(),"fill B");
		turn(now,now.EMPTYA(),"empty A");
		turn(now,now.EMPTYB(),"empty B");	
	}
}

int main()
{      
	while(cin>>A>>B>>C)
	{   flag.clear();path.clear();ppath.clear();  
	    while (!q.empty())q.pop();//对于每一组进行情况
		bfs(0,0);cout<<"success"<<endl;
	} return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值