01分數規劃算法 信息學競賽 OI ACM 二分 Dinkelbach 最優比率生成樹 最優比率環
01分數規劃
張天翔
blog.csdn.net/hzoi_ztx
[email protected]
前置技能
問題模型1
基本01分數規劃問題
給定n 個二元組(valuei,costi) ,valuei 是選擇此二元組獲得的價值(非負),costi 是選擇此二元組付出的代價(非負),設xi(xi∈{0,1}) 代表第i 個二元組的選與不選,最大(小)化下式
maximize(or minimize) r=∑valuei⋅xi∑costi⋅xi
下面先說最大化
解決方法
二分法
設r 最大值爲r∗ ,
r∗=∑valuei⋅xi∑costi⋅xi
∑valuei⋅xi−r∗⋅∑costi⋅xi=0
設一個函數,自變量爲r 值,
f(r)=∑valuei⋅xi−r∗⋅∑costi⋅xi
觀察這個函數,假如{xi} 固定,則這個函數就是座標系中一條直線(y=B−A⋅x ),每一組{xi} 對應着一條直線,這些直線斜率非正(因爲−A=−∑costi⋅xi≤0 ),縱截距非負(因爲B=∑valuei⋅xi≥0 ),如圖1。
對於每一條直線,當f(r)=0 時,橫截距就是這一組的r ,那麼r∗ 就是每條直線橫截距的最大值(每組{xi} 對應r 的最大值)如圖2。
在圖中上任取一條垂直x 軸的豎線,
如果存在直線與這條豎線的交點縱座標爲正,那麼最優值一定在當前豎線的右側;
如果所有直線與這條豎線交點縱座標爲負,那麼最優值一定在當前豎線的左側;
如果所有直線與這條豎線交點縱座標非正且存在直線與這條豎線交點縱座標爲0,那麼當前豎線橫座標即爲最優值r∗ 。
按照這個思想,可以二分答案r ,那麼二分時如何進行判斷呢?
選擇一個r 時需要判斷所有f(r) 的最大值是否爲0,如果max{f(r)}>0 則r<r∗ ;如果max{f(r)}<0 則 r>r∗ 。
怎樣求max{f(r)} ?
f(r)=∑valuei⋅xi−r⋅∑costi⋅xi=∑(valuei−r⋅costi)⋅xi
二分一個r 時,每個二元組的valuei−r⋅costi 都可以求出,設其爲weighti ,現在的目標就是找到一組{xi} 使得∑wighti⋅xi 最大(即求max{f(r)} )。怎麼找到這一組{xi} ,或者直接求得max{f(r)} 呢?具體問題具體分析,經常藉助最短路算法判斷是否存在負環。下面會有幾道例題。
01分數規劃還會與其他問題結合,如網絡流等。
Dinkelbach 算法
這個算法我是在寫這篇文章時才知道的。
思考上述二分算法的思路,設二分過程中某一個二分值爲r ,二分時的判斷條件是max{f(r)} 的正負性,而這個r 除了讓L 右移或者R 左移就沒有用了。現在思考某一過程中r 與max{f(r)} 能否再被利用。
二分時,假如max{f(r)}>0 這說明最優解在當前r 的右側,於是讓L=r ,但是,如果將L 移動到max{f(r)} 對應直線的橫截距呢?顯然,算法會變得更快。這個思想就是Dinkelbach 算法的內涵。
Dinkelbach 實質上是一種迭代算法,基於這樣的思想:不去二分答案,而是先隨便給定一個答案,然後根據更優的解(max{f(r)} 對應直線的橫截距)不斷移動答案,逼近最優解。理論上它比二分快些。
在這個算法中,一般將r 初始化爲0 。
再說最小化
看上面的圖,也很好理解,就是最左邊的r 爲r∗ ,當前的r 確定時需要用到min{f(r)} 。
如果min{f(r)}>0 ,那麼r<r∗ ;
如果min{f(r)}=0 ,那麼r=r∗ ;
如果min{f(r)}<0 ,那麼r>r∗ 。
做題時認清哪個是valuei ,哪個是costi,再記住上面幾張圖,基本不會出錯了。
兩種算法的比較
Dinkelbach 算法的弊端就是需要保存解。這兩個算法解決統一問題實際上都有可能快些。
我覺着我一般還是用二分。。。。
例題
[POJ2976]Dropping tests
問題模型2
最優比率生成樹
帶權無向圖G , 對於圖中每條邊ei , 都有valuei 和costi ,現在求一棵生成樹T ,最大(小)化∑valuei∑costi,ei∈T
解決方法
套用01分數規劃模型,如果ei∈T 則xi=1 否則xi=0 。
二分法
二分答案r ,邊賦值weighti=valuei−r⋅costi ,因爲是生成樹,邊的數量確定,那麼max{f(r)} 需要選取前|G|−1 大的weighti ,也就是求最大生成樹,按最大生成樹權值的正負性就可以二分了。最小化就求最小生成樹。
Dinkelbach 算法
當前答案r ,邊賦值weighti=valuei−r⋅costi ,同樣求最大生成樹,找到max{f(r)} 對應的邊集{xi} ,也就是最大生成樹的邊集。對這個邊集找橫截距當做下一次答案。橫截距是啥呢?
f(r)=B−A⋅rrr=0=B/A=∑valuei⋅xi∑costi⋅xi
最小化就求最小生成樹。
例題
[POJ2728]Desert King
問題模型3
最優比率環
給定有點權和邊權的圖,求一個環,使得環的點權和與邊權和的比值最大。
解決方法
套用01分數規劃模型,點權爲valuei ,邊權爲costi ,一個環爲C
問題要求最大化∑valuei∑costi,(i∈C)
邊數和點數是相同的,但上述式子表述不是很正確,意會即可。
若答案爲r∗ ,那麼任意一個環
∑valuei∑costi∑valueir∗⋅∑costi−∑valuei≤r∗≤r∗⋅∑costi≥0
最小化時
∑valuei∑costi∑valuei∑valuei−r∗⋅∑costi≥r∗≥r∗⋅∑costi≥0
二分法
設當前答案r ,
r<r∗ ,至少存在一個環,r⋅∑costi−∑valuei<0 ,即存在負權迴路(將邊權設爲r⋅costi−valuei ,不是提前算出,而是在更新路徑的時候從哪個點訪問到這條邊的就將這條邊設爲相應點權與邊權的對應值);
r≥r∗ ,則不存在負環。
求負環可以用Bellman-Ford,但是比較慢,一般用spfa算法求負環
具體判斷方法爲,一個點不能入隊n 次,否則有負環;一條最短路徑長度不能到n ,否則有負環。兩個判斷方法可以同時使用。
最小化時邊權設爲 ∑valuei−r⋅∑costi 即可,同樣也是更新時算出此值。
以上具體實現看例題。
Dinkelbach 算法
如果用這個算法需要記錄下來一個負環,實現還是能實現的,但是沒有二分+spfa好寫。
例題
[POJ3621]Sightseeing Cows
問題模型4
最大密度子圖
這個問題會寫在網絡流總結中。
更多
更多題目在01分數規劃中。
參考資料
【1】KirisameMarisa - NYIST 914Yougth的最大化【二分搜索/Dinkelbach算法】
【2】PerSeAwe - [Algorithm]01分數規劃