量杯問題
張衝和好爛
解題概念
(以圖論角度)
1.把一個狀態視為圖上的一個節點
2.我們已經知道初始的節點為全部杯子都為0的狀況 ,目標節點為包含目標水量的某點。
3. 找到目標水量。
How?
先把圖建出來
令一個節點為以下序列\([c_1,c_2,...,c_n]\),量杯大小為\([l_1,l_2,...,l_n]\)
我們可以發現:我們有一條邊\((s\to e)\)
若且唯若下方至少一條件成立
- \(s_{c_i} \neq l_i \text{ and } e_{c_i} = l_i\)
- \(s_{c_i} \neq 0 \text{ and } e_{c_i} = 0\)
- 選定一組 \((i,j)\) \(s.t.\) \(e_{c_i} = s_{c_i} - min(s_{c_i},l_j - s_{c_j})\text{ and }e_{c_j} = min(l_j,s_{c_j} + s_{c_i})\)
且\(\forall k \in [1,n]\text{ and }k \notin \{i,j\}, s_{c_k} = e_{c_k}\)成立
And
我們必須找到使 \(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\)分別表示量杯數及最大量杯容量)
Really?
前述複雜度分析中
我們其實假設了每次檢查一個點是否被走訪都是\(O(1)\)
但實際上卻不一定會是這樣,因此若令檢查的複雜度為\(O(w)\)
則複雜度應為\(O(m^nn^2w)\)
因此若要求實際上的複雜度,我們現在必須考慮\(w\)的值
hash table優化
上禮拜賴昭勳教過的,我想說練習看看。
每次加入節點都要用線性搜尋檢查其是否出現過,這樣每次都是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
若有collision怎麼辦?
1. linear probing:
2. linked list:
Or
回溯解
回溯過程
由於我們在回溯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稍贏
量杯問題papabeard
By Hubert chang
量杯問題papabeard
- 50