量杯問題

credit to 明年校內賽要把我電爛的Hubert Chang

made and presented by yungyao

解題概念

(以圖論角度)

1.把一個狀態視為圖上的一個節點

 

2.我們已經知道初始的節點為全部杯子都為0的狀況 ,目標節點為包含目標水量的某點。

 

3. 找到目標水量。

How?

先把圖建出來

令一個節點為以下序列\([c_1,c_2,...,c_n]\),量杯大小為\([l_1,l_2,...,l_n]\)

我們可以發現:我們有一條邊\((s\to e)\)

若且唯若下方至少一條件成立

  1. \(s_{c_i} \neq l_i \text{ and } e_{c_i} = l_i\)
  2. \(s_{c_i} \neq 0 \text{ and } e_{c_i} = 0\)
  3. 選定一組 \((i,j)\)  \(s.t.\) \(e_{c_i} = s_{c_i} - min(l_j - s_{c_j},s_{c_i})\text{ and }e_{c_j} = min(s_{c_j} + s_{c_i},l_j)\)

且\(\forall k \in [1,n]\setminus \{i,j\}, s_{c_k} = e_{c_k}\)成立

And

我們必須找到使 \(t \in u_c\) 成立的 \(u\) 中

距離起點最短的那個點

換句話說我們在求的是非帶權圖中的的單點源最短路

而這件事可以透過BFS達成

my slides on BFS(and basic graph theory)

複雜度?

由於BFS的複雜度是 \(O(V+E)\)

而點的數量很顯然的是狀態數

而由前述的建圖方式可知以每個狀態為起點的邊

最多有\(n^2 - n + 2n = n^2+n\)個

另外,狀態數則很顯然會屬於\(O(m^n)\)

因此總複雜度為\(O(m^n + m^n(n^2+n)) = O(m^nn^2)\)

(\(n,m\)分別表示量杯數及最大量杯容量)

補充by 8e7

要注意一點是實際上的水量必為\(gcd(l)\)的倍數

再加上bfs不一定會完整跑完整張圖

因此上述複雜度分析僅是一個上界

(量杯問題是NP-Hard source

實際運行速度跟更精確的複雜度可能會更快

Really?

前述複雜度分析中

我們其實假設了每次檢查一個點是否被走訪都是\(O(1)\)

但實際上卻不一定會是這樣,因此若令檢查的複雜度為\(O(w)\)

則複雜度上界應為\(O(m^nn^2w)\)

因此若要求實際上的複雜度,我們現在必須考慮\(w\)的值

hash table優化

上禮拜賴昭勳教過的,我想說練習看看。
​這句by hubert,他裝弱

有一種直觀的想法是逐一檢查已經訪問過的點看是否有重複

但這樣的複雜度將會是線性時間

而我們可以利用hash table的方式

將複雜度降到\(O(1)\)(常數時間)

作法:

1.把一個狀態\((c_1,c_2,c_3,c_4,c_5\))代入hash function (以下使用rolling hash,但其實任意一種hash方式都可,如後面我會使用bitwise的作法)

\(h(c) = \sum\limits_{i=1}^{5}c_i \times {p_1}^{5 - i}, p_1 \text{ is prime}\)

 

2.把\(h(c)\)去模另一個質數\(p_2\)(\(p_2\)必須夠大,以確保collision的機率夠低)

 

3.模完可以確保每個狀態都有對應的index

 

若有collision怎麼辦?

1. linear probing:

 

 

2. linked list:

 

Or

unordered_map

C++ 的 STL幫你解決實作ㄌ(不過hash function要自己寫)

或者你想要更快的話

pb_ds hash table

回溯解

回溯過程

由於我們在回溯BFS的過程

因此只要很簡單地維護每個節點在BFS Tree上的母節點就好

btw

由於你會發現這題狀態數只到\(51^5 < 2^{31}\)

所以你可以把整個狀態以一個int表示

你的hash可以用位元來寫,會滿好寫的

(當然hash也不是什麼難寫的東西,可是位元的常數很好)

但這題也沒有卡常(他卡一個酷酷的數學東西要解掉)

我實測用STL,pb_ds,位元hash都能AC掉

在TIOJ上運行時間:位元 \(<\) STL \(\approx\) pb_ds

雖然說pb_ds理論上要比STL快

但在沒有collision的狀態下,兩者的運行速度甚至是STL稍贏

Code (回溯解版本)

Top Coder

位元映射加上神奇IO優化,可以使你獲得Top Coder><

量杯問題

By yungyao

量杯問題

  • 184