張衝和好爛
(以圖論角度)
1.把一個狀態視為圖上的一個節點
2.我們已經知道初始的節點為全部杯子都為0的狀況 ,目標節點為包含目標水量的某點。
3. 找到目標水量。
先把圖建出來
令一個節點為以下序列\([c_1,c_2,...,c_n]\),量杯大小為\([l_1,l_2,...,l_n]\)
我們可以發現:我們有一條邊\((s\to e)\)
若且唯若下方至少一條件成立
且\(\forall k \in [1,n]\text{ and }k \notin \{i,j\}, s_{c_k} = e_{c_k}\)成立
我們必須找到使 \(t \in u_c\) 成立的 \(u\) 中
距離起點最短的那個點
換句話說我們在求的是非帶權圖中的的單點源最短路
而這件事可以透過BFS達成
由於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\)分別表示量杯數及最大量杯容量)
前述複雜度分析中
我們其實假設了每次檢查一個點是否被走訪都是\(O(1)\)
但實際上卻不一定會是這樣,因此若令檢查的複雜度為\(O(w)\)
則複雜度應為\(O(m^nn^2w)\)
因此若要求實際上的複雜度,我們現在必須考慮\(w\)的值
上禮拜賴昭勳教過的,我想說練習看看。
每次加入節點都要用線性搜尋檢查其是否出現過,這樣每次都是O(n)。若改用hash table,如果有做好的話,幾乎都可以O(1)搜到。
作法:
1.把一個狀態(a,b,c,d,e)代入某
f(a,b,c,d,e) = a*p1^5+b*p1^4 + c*p1^3 + d*p1^2 + e*p1^1 ,p1為某質數
2.把f(a,b,c,d,e)去模另一個質數p2(hash_table的大小)
3.模完可以確保每個狀態都有對應的index
1. linear probing:
2. linked list:
由於我們在回溯BFS的過程
因此只要很簡單地維護每個節點在BFS Tree上的母節點就好
由於你會發現這題狀態數只到\(51^5 < 2^{31}\)
所以你可以把整個狀態以一個int表示
你的hash可以用位元來寫,會滿好寫的
(當然hash也不是什麼難寫的東西,可是位元的常數很好)
但這題也沒有卡常(他卡一個酷酷的數學東西要解掉)
我實測用STL,pb_ds,位元hash都能AC掉
在TIOJ上運行時間:位元 \(<\) STL \(\approx\) pb_ds
雖然說pb_ds理論上要比STL快
但在沒有collision的狀態下,兩者的運行速度甚至是STL稍贏