Pots(POJ - 3414)【BFS 尋找最短路+路徑輸出】

Z發表於2020-10-06

Pots(POJ - 3414)

題目連結

演算法

BFS

1.這道題問的是給你兩個體積分別為A和B的容器,你對它們有三種操作,一種是裝滿其中一個瓶子,另一種是把其中一個瓶子的水都倒掉,還有一種就是把其中一個瓶子的水匯入另一個瓶子中(可能會有剩餘)。最後讓你輸出在能夠得出體積為C的水的情況下操作的最小次數並且把過程輸出。如果無法得出體積為C的水,則輸出“impossible”。

2.這個題主要涉及兩個點,一個是求出最小次數,還有一個就是把路徑輸出。對於這種有目標值的求最小次數問題,我們可以使用bfs解決。初始狀態是兩個瓶子都為空,最終狀態是其中一個瓶子中的水的容量達到了目標值C。在每個狀態下可以對瓶子進行上面描述的三種操作,細分下來其實只有6種操作,分別是:

  • 將A瓶子裝滿水
  • 將B瓶子裝滿水
  • 將A瓶子中的水倒入B瓶子中
  • 將B瓶子中的倒入A瓶子中
  • 將A瓶子中的水全部抽走
  • 將B瓶子中的水全部抽走

我們可以把每種狀態都放入到佇列中,當到達某種狀態時,就分別執行上面6個操作,同時需要注意做好每種狀態的標記,避免重複。

3.為了獲得路徑,我們可以把每次將新的狀態插入佇列中的同時用陣列記錄,可以用結構體來存放每個狀態,該結構體中除了當前A瓶和B瓶中水的容量這兩種屬性外,還要有它本身在陣列中的下標id,父狀態在陣列中的下標pre,到達此狀態時的最小步數steps。由於bfs的特殊性,我們可以認為當達到目標值時的steps為最小最優的(至於為什麼是最優的,我們可以簡單的想bfs因為是一層一層的搜尋的,所以可以認為第一個到達目標值的層數是最小的,當然前提是代價是一樣的,比如這裡每執行一步都表示一次,故可以用bfs實現,而如果執行每種操作的代價不同,就不能用bfs來實現了)。

C++程式碼

#include<iostream>
#include<queue>
#include<stack>
#include<cstdio>
using namespace std;
const int N = 1e6 + 10, M = 1e3;
int a, b, c;
bool st[M][M];
struct Status{
    int ca, cb, pre;
    int ope;    //1表示裝滿A,2表示裝滿B,3表示A倒入B,4表示B倒入A,5表示倒掉A,6表示倒掉B
    int steps;
    int id;
    Status(){
        ca = 0, cb = 0, pre = -1;
        ope = -1;
        steps = 0;
        id = 0;
    }
}s[N];
int cnt;
//裝滿A
void fullA(Status& t)
{
    t.ca = a;
    t.ope = 1;
    t.steps++;
    t.id = cnt;
    //s[cnt++] = t;
}
//倒掉A
void pourA(Status& t)
{
    t.ca = 0;
    t.ope = 5;
    t.steps++;
    t.id = cnt;
    //s[cnt++] = t;
}
//裝滿B
void fullB(Status& t)
{
    t.cb = b;
    t.ope = 2;
    t.steps++;
    t.id = cnt;
    //s[cnt++] = t;
}
//倒掉B
void pourB(Status& t)
{
    t.cb = 0;
    t.ope = 6;
    t.steps++;
    t.id = cnt;
   // s[cnt++] = t;
}
//A倒入B
void pourA_B(Status& t)
{
    if(t.ca >= b - t.cb)
    {
        t.ca -= b - t.cb;
        t.cb = b;
    }
    else
    {
        t.cb += t.ca;
        t.ca = 0;
    }
    t.ope = 3;
    t.steps++;
    t.id = cnt;
    //s[cnt++] = t;
}
//B倒入A
void pourB_A(Status& t)
{
    if(t.cb >= a - t.ca)
    {
        t.cb -= a - t.ca;
        t.ca = a;
    }
    else
    {
        t.ca += t.cb;
        t.cb = 0;
    }
    t.ope = 4;
    t.steps++;
    t.id = cnt;
    //s[cnt++] = t;
}
void print(Status t)
{
    cout << t.steps << endl;
    stack<Status> sta;
    sta.push(t);
    while(true)
    {
        if(t.pre == -1) break;
        t = s[t.pre];
        sta.push(t);
    }
    while(sta.size())
    {
        Status tmp = sta.top();
        sta.pop();
        if(tmp.ope == 1)
            puts("FILL(1)");
        else if(tmp.ope == 2)
            puts("FILL(2)");
        else if(tmp.ope == 3)
            puts("POUR(1,2)");
        else if(tmp.ope == 4)
            puts("POUR(2,1)");
        else if(tmp.ope == 5)
            puts("DROP(1)");
        else if(tmp.ope == 6)
            puts("DROP(2)");
    }
}
void bfs()
{
    Status tmp;
    queue<Status> que;
    que.push(tmp);
    st[tmp.ca][tmp.cb] = true;
    s[cnt++] = tmp;
    while(que.size())
    {
        tmp = que.front();
        que.pop();
        //cout << "***" << tmp.ca << ", " << tmp.cb << endl;
        if(tmp.ca == c || tmp.cb == c)
        {
            //cout << "**end** " << tmp.ca << " , " << tmp.cb << ", " << tmp.pre << endl;
            //列印輸出
            print(tmp);
            return ;
        }
        //迴圈那六種情況
        for(int i = 1; i <= 6; i++)
        {
            Status tmp1 = tmp;
            //cout << "tmp*** " << tmp.ca << ", " << tmp.cb << endl;
            if(i == 1)
            {
                if(tmp1.ca == a) continue;
                fullA(tmp1);
                if(!st[tmp1.ca][tmp1.cb])
                {
                    tmp1.pre = tmp.id;
                    st[tmp1.ca][tmp1.cb] = true;
                    que.push(tmp1);
                    s[cnt++] = tmp1;
                    //cout << "tmp1**1* " << tmp1.ca << ", " << tmp1.cb << endl;
                }

            }
            else if(i == 2)
            {
                if(tmp1.cb == b) continue;
                fullB(tmp1);
                if(!st[tmp1.ca][tmp1.cb])
                {
                    tmp1.pre = tmp.id;
                    st[tmp1.ca][tmp1.cb] = true;
                    que.push(tmp1);
                    s[cnt++] = tmp1;
                    //cout << "tmp1**2* " << tmp1.ca << ", " << tmp1.cb << endl;
                }

            }
            else if(i == 3)
            {
                if(!(tmp1.ca)) continue;
                pourA_B(tmp1);
                if(!st[tmp1.ca][tmp1.cb])
                {
                    tmp1.pre = tmp.id;
                    st[tmp1.ca][tmp1.cb] = true;
                    que.push(tmp1);
                    s[cnt++] = tmp1;
                    //cout << "tmp1**3* " << tmp1.ca << ", " << tmp1.cb << endl;
                }

            }
            else if(i == 4)
            {
                if(!(tmp1.cb)) continue;
                pourB_A(tmp1);
                if(!st[tmp1.ca][tmp1.cb])
                {
                    tmp1.pre = tmp.id;
                    st[tmp1.ca][tmp1.cb] = true;
                    que.push(tmp1);
                    s[cnt++] = tmp1;
                    //cout << "tmp1**4* " << tmp1.ca << ", " << tmp1.cb << endl;
                }

            }
            else if(i == 5)
            {
                if(!(tmp1.ca)) continue;
                pourA(tmp1);
                if(!st[tmp1.ca][tmp1.cb])
                {
                    tmp1.pre = tmp.id;
                    st[tmp1.ca][tmp1.cb] = true;
                    que.push(tmp1);
                    s[cnt++] = tmp1;
                    //cout << "tmp1**5* " << tmp1.ca << ", " << tmp1.cb << endl;
                }

            }
            else if(i == 6)
            {
                if(!(tmp1.cb)) continue;
                pourB(tmp1);
                if(!st[tmp1.ca][tmp1.cb])
                {
                    tmp1.pre = tmp.id;
                    st[tmp1.ca][tmp1.cb] = true;
                    que.push(tmp1);
                    s[cnt++] = tmp1;
                    //cout << "tmp1**6* " << tmp1.ca << ", " << tmp1.cb << endl;
                }

            }
        }
    }
    puts("impossible");
}

int main()
{
    cin >> a >> b >> c;
    bfs();
    return 0;
}

相關文章