Pour water

问题

倒水问题 “fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。
Input
输入包含多组数据。每组数据输入 A, B, C 数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。
Output
你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。

问题分析

倒水问题,A和B的水量有不同的状态。可将其抽象为点,则将各种状态看做一个图,题目转化为找出图中到达一点的最短路径问题。
数据结构:定义了一个结构体存储A,B的状态和达到此状态的操作序号。使用map结构记录当前状态与上一个状态。
使用BFS搜索的基本思路为:
从A,B都为空开始,找到这个状态的所有可能到达的状态,这些点就为下一步能到的点。
然后再把所有的下一步能走到的点,再寻找它下一步能走到的点,一直循环重复直到找到终点状态,即最短路径。
然后再把每一步的操作和路径存储,搜索完过后,根据终点不断找父节点,记录其操作并输出

代码实现

#include<stdio.h>
#include<map>
#include<queue>
using namespace std;

struct status
{
	int a;
	int b;
	int o;
	bool operator < (const status &s) const
	{
		if(a != s.a) return a<s.a;
		else return b<s.b;
	}
};

queue<status> q;
map<status,status> from;

void judge(status &s,status& t)
{
	if(from.find(t) == from.end())//未曾到达 
	{
		from[t]=s;
		q.push(t); 
	}
}

int main()
{
	int A,B,C;
	status s,t;
	while(scanf("%d%d%d",&A,&B,&C) != EOF)
	{
		s.a=0;
		s.b=0;
		s.o=-1;
		q.push(s);
		bool at=true;
		while(at)
		{
			s = q.front();
			q.pop();
			
			if(s.b == C || s.a==C){
				at=false;
			}
			else{
			
			if(s.a < A)
			{
				t.a=A;
				t.b = s.b;
				t.o = 0;
				judge(s,t);
				
				if(s.b != 0)
				{
					if(s.a+s.b>=A)
					{
						t.a=A;
						t.b=s.a+s.b-A;
						t.o=5;
						judge(s,t);
					}
					else{
						t.a = s.a+s.b;
						t.b = 0;
						t.o=5;
						judge(s,t);
					}
				}
			}
			
			if(s.b < B)
			{
				t.a=s.a;
				t.b=B;
				t.o=1;
				judge(s,t);
				if(s.a != 0)
				{
					if(s.a+s.b>=B)
					{
						t.a=s.a+s.b-B;
						t.b=B;
						t.o=4;
						judge(s,t);
					}
					else{
						t.a = 0;
						t.b = s.a+s.b;
						t.o=4;
						judge(s,t);
					}
				}
			}
			
			if(s.a>0)
			{
				t.a=0;
				t.b=s.b;
				t.o=2;
				judge(s,t);
			}
			
			if(s.b>0)
			{
				t.a=s.a;
				t.b=0;
				t.o=3;
				judge(s,t);
			}}
		 }  
		A:
		status ret[100];
		int i=1;
		ret[0] = s;
		while(from.find(s) != from.end() &&!(s.a==0&&s.b==0))
		{
			s = from[s];
			ret[i] = s;
			i++;
		}
		//i = i-2;
		for(;i>=0;i--){
			switch(ret[i].o)
			{
				case 0:printf("fill A\n");break;
				case 1:printf("fill B\n");break;
				case 2:printf("empty A\n");break;
				case 3:printf("empty B\n");break;
				case 4:printf("pour A B\n");break;
				case 5:printf("pour B A\n");break;
			}
     	}
     	printf("success\n");
    }
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值