题目:
倒水问题
“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
思路:
概述:
该题是作业A题的变形,本质也是BFS问题,只不过隐式图问题。
隐式图是仅给出初始结点、目标结点以及生成子结点的约束条件(题意 隐含给出),要求按扩展规则应用于扩展结点的过程,找出其他结点, 使得隐式图的足够大的一部分编程显式,直到包含目标结点为止。
在该类问题中,可能出现的每个点的情况在初始是不知道的,只有在不断执行扩展规则后才可以得到。
数据结构
point:记录该点处的a,b中液体量
Q:存储要进行下一步扩展的点
map<point,point> from :记录第一次到达某个杯子状态的前一个杯子状态,同时可以记录该杯子状态是否被访问过
map<point,int> handle:记录第一次到达某个杯子状态的操作号
解法
step1:将两个杯子均为空的状态加入队列
step2:从队列中取出一个状态,判断是否有杯子中的水满足条件,有-》step3,无-》step4
step3: 对取出状态进行所有倒水操作,分别判断新的状态是否未到达,将满足条件的放入队列中
step4:递归输出从原点到终点的倒水路径
总结:
本题也可以直接使用高维数组记录
代码:
#include<iostream>
#include<queue>
#include<map>
#include<string.h>
using namespace std;
struct point
{
int a,b;
bool operator<(const point &p) const
{
return a!=p.a?a<p.a:b<p.b;
}
};
queue<point> Q;
map<point,point> from;
map<point,int> handle;
void print(point &p)//递归输出从原点到终点倒水的路径
{
point s=from[p];
if(from.find(s)==from.end()||(s.a==0&&s.b==0))//判断是否到达原点
{
switch(handle[p])
{
// case 1:cout<<"success"<<endl;break;
case 2:cout<<"empty A"<<endl;break;
case 3:cout<<"empty B"<<endl;break;
case 4:cout<<"fill A"<<endl;break;
case 5:cout<<"pour B A"<<endl;break;
case 6:cout<<"fill B"<<endl;break;
case 7:cout<<"pour A B"<<endl;break;
}
return;
}
print(from[p]);
switch(handle[p])
{
// case 1:cout<<"success"<<endl;break;
case 2:cout<<"empty A"<<endl;break;
case 3:cout<<"empty B"<<endl;break;
case 4:cout<<"fill A"<<endl;break;
case 5:cout<<"pour B A"<<endl;break;
case 6:cout<<"fill B"<<endl;break;
case 7:cout<<"pour A B"<<endl;break;
}
}
int main()
{
int A,B,C;
while(scanf("%d%d%d",&A,&B,&C)!=EOF)
{
while(!Q.empty())//清空Q、from、handle
Q.pop();
from.clear();
handle.clear();
point u,next;
u.a=0;
u.b=0;
Q.push(u);
while(!Q.empty())
{
point now=Q.front();
Q.pop();
if(now.a==C||now.b==C)//到达终点
{
print(now);
cout<<"success"<<endl;
break;
}
if(now.a>0)//将a倒掉
{
next.a=0;
next.b=now.b;
if(from.find(next)==from.end())//判断该状态是否被到达过
{
from[next]=now;
handle[next]=2;
Q.push(next);
}
}
if (now.b > 0) //将b倒掉
{
next.b = 0;
next.a = now.a;
if(from.find(next)==from.end())
{
from[next]=now;
handle[next]=3;
Q.push(next);
}
}
if(now.a<A)//将b倒入a
{
next.a=A;
next.b=now.b;
if(from.find(next)==from.end())
{
from[next]=now;
handle[next]=4;
Q.push(next);
}
if (now.b != 0)
{
if (now.a + now.b <= A)
{
next.a = now.a + now.b;
next.b = 0;
if(from.find(next)==from.end())
{
from[next]=now;
handle[next]=5;
Q.push(next);
}
} else
{
next.a = A;
next.b = now.a + now.b - A;
if(from.find(next)==from.end())
{
from[next]=now;
handle[next]=5;
Q.push(next);
}
}
}
}
if (now.b < B) //将a倒入b
{
next.a = now.a;
next.b = B;
if(from.find(next)==from.end())
{
from[next]=now;
handle[next]=6;
Q.push(next);
}
if (now.a != 0)
{
if (now.a + now.b <= B)
{
next.a = 0;
next.b = now.a + now.b;
if(from.find(next)==from.end())
{
from[next]=now;
handle[next]=7;
Q.push(next);
}
} else
{
next.a = now.a + now.b - B;
next.b = B;
if(from.find(next)==from.end())
{
from[next]=now;
handle[next]=7;
Q.push(next);
}
}
}
}
// cout<<now.a<<" "<<now.b <<endl;
// cout<<next.a<<" "<<next.b <<endl;
}
}
}