Week2 HomeWork B Pour Water BFS+路径输出

2 篇文章 0 订阅

题目描述

倒水问题 “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列开始,不应该有空行或任何尾随空格。

Sample Input

2 7 5

2 7 4

Sample Output

fill B

pour B A

success

fill A

pour A B

fill A

pour A B

success

Hint

如果你的输出与Sample Output不同,那没关系。对于某个"A B C"本题的答案是多解的,不能通过标准的文本对比来判定你程序的正确与否。 所以本题由 SPJ(Special Judge)程序来判定你写的代码是否正确。

算法分析

​ 倒水问题(隐式图问题)可以用BFS记录可达的状态。另外,可以用类似A题的思路,记录前驱状态,之后递归输出,便可显式输出状态转移过程。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector> 
#include <cstring>
#include <map>
using namespace std;

struct Status
{
	int a,b; //A瓶水量与B瓶水量 
	int type; //变换到当前状态的操作类型 
	
	bool operator < (const Status &s) const
	{
		if(a != s.a) return a < s.a;
		else return b < s.b;
	}	//重载< 
};//状态 

queue<Status> Q; //BFS队列 

map<Status, Status> from; //记录前置状态 

void output(Status &p)
{
	//递归输出 
	if(from.find(p) == from.end() || (p.a == 0 && p.b == 0)) //无前置状态或A、B瓶均没水 
	{
		//printf("<%d,%d>",p.a,p.b);
		return;
	}
	 
	output(from[p]); //递归 
	
	//输出部分 
	if(p.type == 1) printf("empty A\n");
	else if(p.type == 2) printf("empty B\n");
	else if(p.type == 3) printf("fill A\n");
	else if(p.type == 4) printf("pour B A\n");
	else if(p.type == 5) printf("fill B\n");
	else if(p.type == 6) printf("pour A B\n");
	//printf(" |<%d,%d> |\n",p.a,p.b); 
}

//记录两个状态直接的转换类型 
void refresh(Status &s, Status &t,int type)
{
	if(type == 1) t.type = 1;
	else if(type == 2) t.type = 2;
	else if(type == 3) t.type = 3;
	else if(type == 4) t.type = 4;
	else if(type == 5) t.type = 5;
	else if(type == 6) t.type = 6;
	
	if(from.find(t) == from.end())
	{
		from[t] = s;
		Q.push(t);
	}
}

void bfs(int A, int B, int C)
{
	Status s,t;  //s表示当前状态,t表示下一状态 
	s.a = s.b = 0;  
	Q.push(s);
	while(!Q.empty())
	{
		s = Q.front();
		Q.pop();
		if(s.a == C || s.b == C) //A瓶或B瓶内水量为C 
		{
			output(s);
			return;
		} 
		// 倒空A 
		if(s.a > 0) 
		{
			t.a = 0;
			t.b = s.b;
			refresh(s, t, 1);
		}
		// 倒空B 
		if(s.b > 0) 
		{
			t.b = 0;
			t.a = s.a;
			refresh(s, t, 2);
		}
		//倒满A
		if(s.a < A)  
		{
			t.a = A;
			t.b = s.b;
			refresh(s, t, 3);
			if(s.b != 0) 
			{
				//B倒入A
				if(s.a + s.b <= A)  
				{
					t.a = s.a + s.b;
					t.b = 0;
					refresh(s, t, 4); 
				}
				else 
				{
					t.a = A;
					t.b = s.a + s.b - A;
					refresh(s, t, 4);
				}
			}
		}
		//倒满B
		if(s.a < B)  
		{
			t.a = s.a;
			t.b = B;
			refresh(s, t, 5);
			if(s.a != 0) 
			{
				//A倒入B 
				if(s.a + s.b <= B) 
				{
					t.a = 0;
					t.b = s.a + s.b;
					refresh(s, t, 6); 
				}
				else 
				{
					t.a = s.a + s.b - B;
					t.b = B;
					refresh(s, t, 6);
				}
			}
		}	
	}
}

//初始化BFS队列 
void clear(queue<Status> & q)
{
	queue<Status> empty;
	swap(empty, q);
}

int main()
{
	int a,b,c;
	while(~scanf("%d%d%d",&a,&b,&c))
	{
		//初始化 
		clear(Q);
		from.clear();
		
		bfs(a, b, c);
		printf("success\n");
	}
	
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值