倒水问题
一、题目:
倒水问题 “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;
}