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;
}
posted @ 2024-07-10 11:21  薛定谔的AC  阅读(2)  评论(0编辑  收藏  举报