1. 程式人生 > >4474 Yet Another Multiple Problem(HDU)

4474 Yet Another Multiple Problem(HDU)

題意理解

給定一個數n(0<n<10000),和一組共m個個位數,要求n的倍數不包含m個個位數的最小值,不存在返回-1。

問題分析

用數位BFS搜尋演算法

轉1:個位數0-9共10種,排除m種後還剩10-m種取值,這10-m個數字任意組合後的數是n的最小倍數就是所求的數字。

轉2:10-m個數字任意組合可以看成是:1位數字組合,2位數字組合,3位數字組合。。。第一個組合能整除n就是所求的數。但這種組合數字的情況太多,如果不存在這樣的數,那麼遍歷就沒有結束狀態。

轉3:找整除n的規律,大數求餘的方法:比如123求5的餘數,先計算1%5 = 1,(1×10+2)%5=2,(2×10+3)%5=3。基於這個方法,我們可以按如下順序搜尋,一位數是0,1,2,...,9,然後基於1的兩位數10,11,12,...,19,基於2的兩位數20,21,22,23,...,29,可以理解為這是一個10-m叉樹,每個節點對應數的某一位,樹根是最高位樹,葉子節點是個位數。

注1:對於終結狀態的處理,按照上面方法的搜尋,對於每個數的餘數,範圍在0~n-1之間,如果搜尋到某個節點的餘數和前面的相同,可以不記錄這個節點的數字。因為A<B且A%n = B%n, 那麼A×10+C<B×10+C, (A×10+C)%n = (B×10+C)%n。這個過程相當於對樹進行了剪枝。終結狀態就是遍歷完所有的餘數1~n-1。0表示整除。

注2:當搜尋到整除n時,如何輸出這個數?用n長度的陣列text記錄遍歷的順序,用n長度的陣列pre記錄節點的雙親。當搜尋到整除n時,用pre陣列向上找雙親節點,輸出從個位到最高位的數字,再把它倒過來就是所求的數。實際是樹的雙親表示法。

注3:每個節點的數用‘0’+數值儲存,string庫拼接倒過來的數,用algorithm的reverse方法將它正過來,再用puts(str.c_str())輸出。這樣就不用顯式使用棧了。

其他

此題沒做出來,bfs第一次這個使用,學習了

雙親表示法很管用,解決了問題,很好很好。

演算法刷的速度明顯慢了,這個月專案做了一個基準集。打算每天晚上做一題。這樣下去心裡慌的一比。

程式碼連結

https://github.com/xierensong/learngit/blob/master/hdu/4474/h4474.cpp