题目
倒水问题 “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
思路
为隐式图问题,采用bfs的思想,以初始状态两杯为空作为起点,六种操作作为六种方向进行遍历。声明map<Status,Status> from,用于记录每次操作后A、B杯的状态,其中from[t]=s即t状态经由s状态得来。
输出采用递归方法,同时根据当前from[t]=s的s状态与t状态判断该状态变化是由哪种操作得来的。
代码
#include <iostream>
#include <queue>
#include <map>
using namespace std;
struct Status{
int a,b;
Status(){};
Status(int _a,int _b){
a=_a;
b=_b;
}
bool operator<(const Status &s)const{//符号重载 const!!
return a!=s.a ? a<s.a : b<s.b;
}
};
map<Status,Status> from;
queue<Status> q;
void refresh(Status s,Status t){
if(from.find(t)==from.end()){//判断合法,即该状态未到达过
from[t]=s;
q.push(t);
}
}
void judge(Status s,Status t){
int tmp1=t.a-s.a;
int tmp2=t.b-s.b;
if(tmp1+tmp2!=0){
if(tmp1>0)
cout<<"fill A"<<endl;
else if(tmp2>0)
cout<<"fill B"<<endl;
else if(tmp1<0)
cout<<"empty A"<<endl;
else if(tmp2<0)
cout<<"empty B"<<endl;
}
else{
if(tmp1>0)
cout<<"pour B A"<<endl;
else
cout<<"pour A B"<<endl;
}
}
void output(Status s){//递归输出
if(from[s].a==0&&from[s].b==0){
judge(from[s], s);
return;
}
output(from[s]);
judge(from[s], s);
}
void bfs(int A,int B,int C){
Status s(0,0);//初始两个杯子为空
q.push(s);
while (!q.empty()) {
Status now=q.front();
q.pop();
if(now.a==C||now.b==C){
output(now);
cout<<"success"<<endl;
return;
}
//根据六种转移方式应满足的必要条件分类列出六种转移方式,可合并
Status next;
//倒空A杯的必要条件是A杯不为空
if(now.a>0){
next.a=0;
next.b=now.b;
refresh(now, next);
}
//倒满A杯的必要条件是A杯不满
if(now.a<A){
next.a=A;
next.b=now.b;
refresh(now, next);
}
//把A杯倒到B的必要条件是A不空B不满
if(now.a>0&&now.b<B){
//B倒满或A倒空
if(now.a<B-now.b){//A倒空
next.a=0;
next.b=now.a+now.b;
}
else{//B倒满
next.a=now.a-(B-now.b);
next.b=B;
}
refresh(now, next);
}
//倒空B杯的必要条件是B杯不为空
if(now.b>0){
next.b=0;
next.a=now.a;
refresh(now, next);
}
//倒满B杯的必要条件是B杯不满
if(now.b<B){
next.b=B;
next.a=now.a;
refresh(now, next);
}
//把B杯倒到A的必要条件是B不空A不满
if(now.b>0&&now.a<A){
//A倒满或B倒空
if(now.b<A-now.a){//B倒空
next.b=0;
next.a=now.b+now.a;
}
else{//A倒满
next.b=now.b-(A-now.a);
next.a=A;
}
refresh(now, next);
}
}
}
int main() {
int a,b,c;
while(cin>>a>>b>>c){
from.clear();
while(!q.empty())
q.pop();
bfs(a,b,c);
}
return 0;
}
总结
pour A B时可不用if语句,而是用next.a=max(0,now.a+now.b-B),next.b=min(now.a+now.b,B);pour B A同理
题目链接