POJ 3414 Pots
题目链接:POJ 3414 【Pots】
思路
对于每个A、B瓶的每个状态,使用结构体存储,同时pre存储操作前的状态的下标,方便回溯查询正确路径的操作,oper存储使用什么操作得到当前状态,operNumber存储到达当前状态需要几步。由于需要求的是最少的操作次数,所以使用BFS,依次增加操作次数,逐层搜索,对于当前状态分别进行六种操作:1.将A装满,2.将B装满,3.将A倒掉,4.将B倒掉,5.将A倒入B中,6.将B倒入A中。同时对于之前出现过的状态,则continue,因为前面出现过的状态,在前面出现时的操作次数肯定比现在要小,所以剪枝,没出现过的状态直接放入队列中继续操作,直到找出满足题目要求的状态为止。
代码
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
#define ll long long
const int N = 1e3 + 10;
int a, b, c, counts;
bool vis[N][N];
string oper[10] = {"", "FILL(1)", "FILL(2)", "DROP(1)", "DROP(2)", "POUR(1,2)", "POUR(2,1)"};
struct pot {
int a, b, pre, oper, operNumber, No;
bool operator<(const pot &c) const { return operNumber > c.operNumber; }
}pots[100010];
void answer(int x) {
int store[100010], cnt = 0;
// 找出正确路径上的所有操作
while (x != -1) {
store[++cnt] = pots[x].oper;
x = pots[x].pre;
}
// 由于最后一个找出来的是初始节点,初始节点对应的操作是"",所以可以不输出初始节点的操作
for (int i = --cnt; i > 0; i--) {
cout << oper[store[i]] << endl;
}
}
void bfs(struct pot start) {
priority_queue<pot> q;
q.push(start);
vis[start.a][start.b] = true;
start.No = counts;
pots[counts++] = start;
while (!q.empty()) {
pot pre = q.top();
// 判断当前状态是否满足题目要求
if (pre.a == c || pre.b == c) {
cout << pre.operNumber << endl;
answer(pre.No);
return;
}
for (int i = 1; i <= 6; i++) {
pot now = pre;
// 把a倒满
if (i == 1) {
now.a = a;
} else if (i == 2) {
now.b = b;
} else if (i == 3) {
now.a = 0;
} else if (i == 4) {
now.b = 0;
} else if (i == 5) {
if (now.a + now.b > b) {
now.a = now.a + now.b - b;
now.b = b;
} else {
now.b = now.a + now.b;
now.a = 0;
}
} else {
if (now.a + now.b > a) {
now.b = now.a + now.b - a;
now.a = a;
} else {
now.a = now.a + now.b;
now.b = 0;
}
}
// 当当前状态每出现过时,标记当前状态,并加入队列中
if (vis[now.a][now.b] == false) {
now.oper = i;
now.operNumber = pre.operNumber + 1;
now.No = counts;
now.pre = pre.No;
pots[counts++] = now;
vis[now.a][now.b] = true;
q.push(now);
}
}
// 删除当前状态
q.pop();
}
// 输出找不到方法的impossible
cout << "impossible" << endl;
}
int main() {
cin >> a >> b >> c;
bfs({0, 0, -1, 0, 0, 0});
return 0;
}