题目链接:3414 -- Pots
You are given two pots, having the volume of A and B liters respectively. The following operations can be performed:
- FILL(i) fill the pot i (1 ≤ i ≤ 2) from the tap;
- DROP(i) empty the pot i to the drain;
- POUR(i,j) pour from pot i to pot j; after this operation either the pot j is full (and there may be some water left in the pot i), or the pot i is empty (and all its contents have been moved to the pot j).
Write a program to find the shortest possible sequence of these operations that will yield exactly C liters of water in one of the pots.
Sample Input
3 5 4
Sample Output
6 FILL(2) POUR(2,1) DROP(1) POUR(2,1) FILL(2) POUR(2,1)
题意:
给两杯水的容量,并且可执行6种操作,对应灌满,倒完,从一杯倒到另一杯。
问最少几步做到,并按顺序输出对应操作。
解题思路:
考虑bfs,路径记录使用数组,在node处添加父节点。但是STL里的queue不会保存节点,所以用伪queue,用node fa回溯路径信息。
用数组做伪queue,和栈模拟有异曲同工之妙!
上代码:
/*Keep on going Never give up*/
#include <bits/stdc++.h>
using namespace std;
#define MAX 0x7fffffff
#define pi acos(-1.0)
//int mon[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
typedef long long ll;
const int N = 1e3 + 5;
const long double eps = 1e-12;
ll a, b, c;
string ans[] = { "FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)" };//不同操作;
struct node {
ll numa, numb, index, step, fa;
}_queue[N*N],now;
bool vis[N][N];
void move(ll na, ll nb, ll& ta, ll& tb, ll i) {
if (i == 0) {
ta = a;
tb = nb;
}
if (i == 1) {
tb = b;
ta = na;
}
if (i == 2) {
ta = 0;
tb = nb;
}
if (i == 3) {
tb = 0;
ta = na;
}
if (i == 4) {
if (na >= (b - nb)) {
ta =na- (b - nb);
tb = b;
}
else
ta = 0, tb = na + nb;
}
if (i == 5) {
if (nb >= (a - na)) {
tb =nb- (a - na);
ta = a;
}
else
tb = 0, ta = nb + na;
}
}
string aans[N];
ll bfs() {
_queue[0] = { 0,0,-1,0,-1 };
ll head = 0, last = 1;//用head节点和last节点模仿出队入对的操作;
while (last > head) {
now = _queue[head];
vis[now.numa][now.numb] = 1;
if (now.numa == c || now.numb == c) {
cout << now.step << endl;
ll len = now.step;
for (ll i = now.step; i > 0; i--) {
aans[i] = ans[now.index];
now = _queue[now.fa];//回溯父节点;
}
for (ll i = 1; i <= len; i++)
cout << aans[i] << endl;
return 1;
}
for (ll i = 0; i < 6; i++) {
ll ta, tb;
move(now.numa, now.numb, ta, tb, i);
if (!vis[ta][tb])
{
vis[ta][tb] = 1;
_queue[last] = { ta,tb,i,now.step + 1,head };
last++;
}
}
head++;
}
return -1;
}
int main() {
cin >> a >> b >> c;
ll ans = bfs();
if (ans == -1)
cout << "impossible";
return 0;
}
ps:回溯路径要么用指针,要么用下标,但是不变的是节点保存,用数组bfs才合适。