POJ3414:POTS(记录路径bfs)

阅读 95

2022-03-12

题目链接:3414 -- Pots

You are given two pots, having the volume of A and B liters respectively. The following operations can be performed:

  1. FILL(i)        fill the pot i (1 ≤ ≤ 2) from the tap;
  2. DROP(i)      empty the pot i to the drain;
  3. 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才合适。

精彩评论(0)

0 0 举报