倒水问题

倒水问题

一、题目:
倒水问题 “fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。

二、输入:
输入包含多组数据。每组数据输入 A, B, C 数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。

三、输出:
你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。

四、样例输入输出:
input

2 7 5
2 7 4

output

fill B
pour B A
success
fill A
pour A B
fill A
pour A B
success

五、解题思路:
bfs隐式图问题。
(1)共有倒空A、倒空B、装满A、装满B、将A倒入B、将B倒入A六种状态。到达一种状态后,下一次操作可以进行这六种情况中的任意一种,类似于bfs思想。
(2)定义结构体【包含A,B,操作mes】,使用队列结构进行储存,同时使用map记录操作的顺序,判断操作后A,B情况在map中不存在,防止死循环。进而在map中将该A,B,mes状态与前一种A,B,mes相关联,同时将该A,B,mes情况压入队列。
(3)递归输出时,从末状态进行查找。通过一个A,B,mes状态,可以在map中查找到其上一步状态,直至查找到起始状态,完成递归输出。

六、实现代码:

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

string message[7]={"success","empty A","empty B","fill A","fill B","pour A B","pour B A"};
struct cups{
	int a,b,mes;
	bool operator<(const cups &s) const{
		return a!=s.a ? a<s.a : b<s.b;
	}
};
queue<cups> Q;
map<cups, cups> m;

void out(cups p){
	if(p.a==0&&p.b==0){
		return;
	}
	out(m[p]);
	cout<<message[p.mes]<<endl;
}

void check(cups s,cups t){      //判断map中不存在该状态,则加入队列,同时记录其前一个状态 
	if(m.find(t)==m.end()){
		m[t]=s;
		Q.push(t);
	}
}

void bfs(int A,int B,int C){
	while(!Q.empty())
		Q.pop();
	m.clear(); 	
	cups s,t;
	s.a=0;s.b=0;s.mes=0;
	Q.push(s);
	
	while(!Q.empty())
	{
		s=Q.front();
		Q.pop();
		if(s.a==C||s.b==C){
			out(s);
			cout<<message[0]<<endl;
			return;
		}
		if(s.a>0){         //A倒空 
			t.a=0;
			t.b=s.b;
			t.mes=1;
			check(s,t);
		}
		if(s.b>0){     //B倒空 
			t.b=0;
			t.a=s.a;    
			t.mes=2;   
			check(s,t);
		}
		if(s.a<A){       //A倒满 
			t.a=A;
			t.b=s.b;
			t.mes=3;
			check(s,t);
			
			if(s.b!=0){
				if(s.a+s.b<=A){
					t.a=s.a+s.b;
					t.b=0;
					t.mes=6;
					check(s,t);
				}
				else{
					t.a=A;
					t.b=s.a+s.b-A;
					t.mes=6;
					check(s,t);
				}
			} 
			
		}
		if(s.b<B){   //B倒满 
			t.a=s.a;
			t.b=B;
			t.mes=4;
			check(s,t);
			
			if(s.a!=0){
				if(s.a+s.b<=B){
					t.b=s.a+s.b;
					t.a=0;
					t.mes=5;
					check(s,t);
				} 
				else{
					t.b=B;
					t.a=s.a+s.b-B;
					t.mes=5;
					check(s,t);
				}
			}
		} 
	}
}
int main(){
	int a,b,c;
	while(scanf("%d %d %d",&a,&b,&c)!=EOF){
    	bfs(a,b,c);	
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值