某天,家父加班晚歸,在飯桌上感嘆工作之不易。我隨口一問,問題來源於水果手機出新品的時候,需要將手裏的貨分配給若幹個代理商。每個代理商都提出了需求(某種機型需要多少台),然而因為資源有限,公司給每個代理商設定了一個分配上限(分配給這家代理商的手機總數不能超過上限)。代理商大概有幾百家,水果手機按顏色、記憶體、尺寸也能分出十幾種,總庫存上千。家父與其夥伴每次都手動分配、調整,有時甚至需要數個小時,十分無奈。
-- Version 0 --
我一看,這不妥妥的
最大流嗎,建立一個二部圖,一側表示手機機型,另一側表示代理商。手機存貨量透過源點到手機機型的邊控制,代理商上限透過代理商到匯點的邊控制,代理商需求用手機機型和代理商間的連邊控制,不就可以了嗎?
-- Version 1 --
家父便給了我一個以前的任務來測試。當然不到一秒就跑出結果來了。但是,家父指出一個問題,就是 不同代理商的優先級是不一樣的 ,配額高的代理商,應該優先分配。
再一看,喲,妥妥的
最小費用最大流啊,給每個流賦一個權重,流向不同的代理商有不同的權重,完美。
-- Version 2 --
家父表示這次的結果能看了許多,但仍然有一個問題:這樣分配出來,一個代理商往往會得到特別多的某種機型,而其余機型則一台都得不到,這個在現實中也不太合理。
唔,這次要求流向統一代理商的不同機型盡量均勻啊。這個我沒想到特別優雅的解決方案,我只是稍微改了一下演算法的實作:在上面的演算法中,每一輪計算都會盡可能分配一堆某種手機給同一代理商,於是我改成了每次計算只分配一台,而且在有多種方案時隨機選擇一種。
這樣跑出來的結果就合理多啦!不過效率低了不少,大概得跑半分鐘吧。
-- Version 3 --
演算法上的改進就沒有啦,不過畢竟不能讓家父在終端跑程式,所以拿C#擼了個界面,讀入某種格式的csv檔,算出結果填到csv裏再輸出出去(講道理在Excel裏寫vba估計也行,不過我之前演算法拿C++寫的,改C#容易些)。最後從網上抄了個進度條,使用者體驗max!
從此以後,家父與其夥伴可以在半個小時內解決問題(畢竟還要微調一下,數據錄入之類的)。
-- 分割線 --
這個故事告訴我們,學演算法還是有用的!
-- 再次分割 --
13年我回高中夏令營演講的時候,我將 編程 這一技能比喻為資訊時代的 駕駛 ,每個人能可以並且應該去學習、掌握。有趣的是,當時收到一份反饋,說駕駛不僅僅是技能,它還可以給人以愉悅之享受。今天回過頭來看這個反饋,突然明白了,這種愉悅某種程度上源自於你獲得的 操控感 。可巧的是,編程也可以帶來極強的操控感。在資訊時代,對手中 數據 的操控能力是極為重要的。