题意:
给你两个容器,容量分别为A, B ,问是否能够经过有限的步骤倒水, 得到容量为 C 的水。
输入:
输入包含多组数据。每组数据输入 A, B, C 数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。
输出:
你的程序的输出将由一系列的指令组成。这些输出行将导致某一个罐子(不指定是哪一个罐子)正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。“fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空,以此类推。
输入样例:
2 7 5
2 7 4
输出样例:
fill B
pour B A
success
fill A
pour A B
fill A
pour A B
success
解题思路:
如果是上BFS算法程序设计课之前,我大概只隐约记得离散数学上讲过好像要用到状态转移方程的思想,似乎还与图论有关。现在知道了这是一类叫做隐式图问题的图论问题,属于BFS遍历算法的应用。题目中的每一种水的状态都对对应于图中的一个点,题意就是从其实状态所代表的点寻找路径到最终状态所表示的点,且每一个点不要重复访问(即不重复到达之前的状态)。助教在课上也给出了自己的参考代码,用结构体来书写每个水杯的状态status,建立的BFS使用的队列也是status结构体类型的,映射map<Status, bool> mp用来表示某一状态是否被访问过,类似于vis二维数组,映射map<Status, string> from用来记录每个状态由来所经过的动作,例如:“pour A B”,便于后面输出这些动作(即状态转移的过程)。映射map<Status,Status> from2用来记录每一个状态的前继状态。遍历过程和一般的BFS遍历类似,只是每一个点成为了每一种状态。最后输出依然可以选择递归实现或利用vector(stack)。
注意事项:
1、map会对status结构体进行自动排序,故必须重载运算符’<’。
2、由于题目要求处理多种不同的情况,因此每次进入循环前要清空所要用到的数据结构。
参考代码:
#include <bits/stdc++.h>
using namespace std;
int A, B, C;
struct Status {
int x, y;
Status() {}
Status(int _x, int _y) {
x = _x;
y = _y;
}
bool operator<(const Status &b) const {
return x == b.x ? y < b.y : x < b.x;
}
Status AToB() {
Status c;
c.x = max(x + y - B, 0);
c.y = min(B, x + y);
return c;
}
Status BToA() {
Status c;
c.y = max(x + y - A, 0);
c.x = min(A, x + y);
return c;
}
Status FillA() {
return Status(A, y);
}
Status FillB() {
return Status(x, B);
}
Status EmptyA() {
return Status(0, y);
}
Status EmptyB() {
return Status(x, 0);
}
};
map<Status, bool> mp;
map<Status, string> from;
map<Status,Status> from2;
queue<Status> q;
void print(Status t) {
if (from.find(t) != from.end()) {
print(from2[t]);
cout<<from[t]<<endl;
}
}
void bfs(int a, int b) {
Status t(a, b);
q.push(t);
mp[t] = 1;
while (!q.empty()) {
t = q.front();
q.pop();
if (t.x == C || t.y == C) {
print(t);
return;
}
Status x=t.AToB();
if (mp[x] == 0) {
mp[x] = 1;
q.push(x);
from[x]="pour A B";
from2[x]=t;
}
x=t.BToA();
if (mp[x] == 0) {
mp[x] = 1;
q.push(x);
from[x]="pour B A";
from2[x]=t;
}
x=t.FillA();
if (mp[x] == 0) {
mp[x] = 1;
q.push(x);
from[x]="fill A";
from2[x]=t;
}
x=t.FillB();
if (mp[x] == 0) {
mp[x] = 1;
q.push(x);
from[x]="fill B";
from2[x]=t;
}
x=t.EmptyA();
if (mp[x] == 0) {
mp[x] = 1;
q.push(x);
from[x]="empty A";
from2[x]=t;
}
x=t.EmptyB();
if (mp[x] == 0) {
mp[x] = 1;
q.push(x);
from[x]="empty B";
from2[x]=t;
}
}
}
int main() {
while (cin >> A >> B >> C) {
mp.clear();
from.clear();
from2.clear();
ans.clear();
while (!q.empty())q.pop();
bfs(0, 0);
cout<<"success"<<endl;
}
return 0;
}