POJ 3414 Pots

薛定谔的AC發表於2024-07-10

題目連結: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;
}