190 likes | 262 Views
Search (I). for Sprout 2014 by Yuan. 搜尋. 聽起來就很慢 …… 但是 , 無計可施的時候 , 你也只能這樣做 XD 在這個年代 呢 … 資訊界許多好做的問題做得差不多了 , 但是世界上實際的問題 , 模型都不太漂亮 …… 所以就只能暴力搜尋了 , 太複雜了 其中搜尋的過程 ,也許可以透過一些以前學過的演算法加速 可是 … 要怎麼搜尋會比較快 ?. 位元運算. 大家還記得位元運算嗎 XD 一個 32 位元的數 , 可以儲存 32 格 0/1 的狀態
E N D
Search (I) for Sprout 2014 by Yuan
搜尋 • 聽起來就很慢…… • 但是, 無計可施的時候, 你也只能這樣做 XD • 在這個年代呢…資訊界許多好做的問題做得差不多了, 但是世界上實際的問題, 模型都不太漂亮…… • 所以就只能暴力搜尋了, 太複雜了 • 其中搜尋的過程,也許可以透過一些以前學過的演算法加速 • 可是…要怎麼搜尋會比較快?
位元運算 • 大家還記得位元運算嗎 XD • 一個32位元的數, 可以儲存32格0/1的狀態 • 01011011001010100100100101010101 • 換句話說, 我們讓原本需要32單位時間的運算縮減成1個單位!
背包問題 • 有N樣物品, N<=40 • 物品的價值<=100000000000000000 • 希望選若干個物品, 湊出恰好總和價值為M • 該怎麼選 ?
我把它搜完!! • 物品數量 N=40 • 每種物品都有可能選取或是不選 • 恭喜你! 我們獲得了 O(2^40) 的時間複雜度!!!!! • 說不定我們可以好好的剪枝, 讓他跑得比較快一點? • TOJ上有, 你可以試試看……
該怎麼辦 • 有沒有可能有很棒的演算法呢…? • 例如 O(n^3) 或 O(n^4) 之類的? • 且慢!! 這是NP-Complete問題 • 為什麼是 NP-Complete~~~by 興國哥 • 總而言之, 現代人類認為這類的問題不太可能有很棒的解法 • 至少至少需要對於問題規模 n 成指數等級的時間複雜度 • 例如 O(2^n), O(3^n), ……
那麼… • 沒有太好的方法, 但難道真的不可能有更好一點點的解法了嗎? • 想一想:N大約為多少的時候, 我們可以輕鬆做出來呢? • N=10, 執行時間約10us • N=20, 執行時間約10ms • N=30, 執行時間約10s…勉強可以忍受 • N=40, ……………………… 10000s 天荒地老的三小時 • 換句話說, 只要有機會讓 N再小一點點 我們就有機會可以做!
之前的經驗 • 如果我們可以把問題分割成”規模相近”,的兩部分 • 而且可以用”好方法”把問題的兩個部分合併 • 那就有機會藉此減少時間複雜度! • 40個物品…任意分割成兩個大小類似的集合
左半邊可以組合出什麼組合呢 • {}、{3}、{7}、{12}、{3,7}、{3,12}、{7,12}、{3,7,12} • 總和分別為 {0,3,7,12,10,15,19,33} • 那麼, 右半邊呢 • {}、{5}、{1}、{4}、{5,1}、{1,4}、{5,4}、{5,1,4} • 總和分別為 {0,5,1,4,6,5,9,10}
如果我們想要湊出總和為 M 的總和 • 左半邊總和分別為 {0,3,7,12,10,15,19,33} • 右半邊總和分別為 {0,5,1,4,6,5,9,10} • 如果左邊所取的物品, 價值總和為 i • 右邊就必須拿到 M-i
流程: • 分別考慮左邊的所有物品能湊出的價值 • 右邊也一樣 • 需要多少時間? 分別需要 O(2^(N/2)) • 我們總共想要價值M • 瓊舉左邊集合的所有價值 i • 如果在右邊找的到 M-i, 那就成功了! • 如果右邊找不到M-i呢? 那就表示不存在”從左邊集合取出總和i, 右邊集合取出總和 M-i的方法”
如何從右邊的集合中尋找 M-i呢? • 先排序! 再搜尋 • O(log(2^(N/2))) • O(2^20 * log2 (2^20)) • 大約 10ms * 20 = 200ms~! • 可以接受! • 雖然不太爽, 但至少比原先的 O(2^40) 快多了
進一步探討 • 要如何找出一組可行的方案? • Struct XDDD { • long long sum; //儲存總和 • bool used[N]; //紀錄每個元素是否用到 • } • 位元運算終於派上用場了!
Struct XDDD {//照sum排序 • long long sum; //儲存總和 • int used; //紀錄每個元素是否用到, 用一個int就過了 • } • 因為搜索的問題本身規模不會太大, • 位元運算是方便好寫的好選擇! • 很快, 很節省空間
還記得這張圖嗎~~ • 搜尋的順序
木棒問題 • 許多等長的木棒 • 隨機切成很多份 • 例如 長度=10 共有三根 • 10 = 2+5+3 • = 5+4+1 • = 3+4+3 • 給你切斷後的長度 • 1,2,3,3,3,4,4,5,5 • 請求出原始木棒可能的最小長度
加速每個步驟的時間 • 讓錯誤盡早發生, 上下界如果已經沒機會了, 就別再執著了 • 盡量不考慮重複的方案 (*因為會浪費時間) • 搜尋的順序(*), 方案替代(*) • 跳過重複的可能(*)