三個桶等分八升水

三個桶等分八升水

​ 有這樣一道智力題目:有三個容積分別是3升、5升和8升的水桶,其中容積爲8升的水桶中裝滿了水,容積爲3升和容積爲5升的水桶是空的。3個水桶都沒有體積刻度,現在需要將大水桶中的8升水等分成兩份,每份都是4升水,附加條件是隻能使用另外兩個空水桶,不能借助其他輔助容器。

​ 這是一個很經典的問題,但是並不難,大部分人都可以在一分鐘內給出答案。不過,很多人可能沒有注意到,這個問題的答案不止一個。先來看一個最常見的答案,也是目前已知最快的操作步驟,一共倒水7次。

1)從8升水桶中倒5升水到5升水桶中
2)從5升水桶中倒3升水到3升水桶中
3)從3升水桶中倒3升水到8升水桶中
4)從5升水桶中倒2升水到3升水桶中
5)從8升水桶中倒5升水到5升水桶中
6)從5升水桶中倒1升水到3升水桶中
7)從3升水桶中倒3升水到8升水桶中

​ 最後的結果是5升水桶和8升水桶中各有升水,其實還有很多種答案,我們就不一一列舉了,到底有多少種答案?水從水桶間倒來倒去,情況太多了,我們算不出來,但是計算機可以。設計一個算法,讓計算機幫助我們把所有的答案都找出來,這就是本章的內容。

問題與求解思路

​ 如果用人的思維方式,那麼解決這個問題的關鍵是怎麼通過倒水湊出確定的1升水或能容納1升水的空間,三隻水桶的容積分別是3、5和8,用這三個數做加減運算,可以得到很多組答案,例如:

3 - (5 - 3) = 1

​ 但是計算機並不能理解這個“1”的重要性,很難按照人類的思維方式按部就班地推導答案,因此計算機解決這個問題,通常會用“窮舉法”。爲什麼用“窮舉法”呢?因爲這不是一個典型意義上的求解最優解的問題,雖然可能暗含了求解倒水次數最少的方法的要求,但就本質而言,常用的求解最優解問題的高效方法都不適用於此問題。如果能夠窮舉解空間的全部合法解,然後通過比較找到最優解也是一種求解最優解的方法。

倒水動作的數學模型

​ 一個合法的倒水動作包含三個要素:倒出水的桶、倒入水的桶和倒水體積。我們用一個三元組來描述倒水動作:<font face =“consolas">{from, to, water}from是指從哪個桶中倒水,to是指將水導向哪個桶,water是此次倒水動作所倒的水量。倒水動作的數據結構定義如下。

typedef struct tagACTION{
    int from;
    int to;
    int water;
}ACTION;

​ 包含動作的倒水狀態定義如下:

struct BucketState
{
    ···
    int bucket_s[BUCKET_COUNT];
    ACTION cuiAction;
};

狀態樹的遍歷

bool BucketState::CanTakeDumpAction(int from, int to)
{
    assert((from >= 0) && (from < BUCKETS_COUNT));
    assett((to >= 0) && (to < BUCKETS_COUNT));
    
    if( (from != 0)
       && !IsBucketEmpty(from)
       && !IsBucketEmpty(to) )
    {
        return true;
    }
        
    return false;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章