1. 程式人生 > >0-1分數規劃問題

0-1分數規劃問題

【問題定義】

求出解集{xi|xi=01}使目標(c1x1+c2x2+...+cnxn)/(d1x1+d2x2+…+dnxn)=cx/dx達到最大。 

【解題思路】

對於分數規劃問題,許多演算法都能利用下面的線性目標函式解決問題。
    Q(L): 最小化cx-Ldx,xi∈{0,1}
    記z(L)為Q(L)的最值。令x*為分數規劃的最優解,並且令L*= (cx*)/(dx*),即分數規劃的最值。
    那麼:z(L) > 0   當且僅當   L<L*
               z(L) = 0   當且僅當   L=L*
               z(L) < 0   當且僅當   L>L*
因此,解決分數規劃問題在本質上等同於尋找L=L*使z(L)=0。出於此目的,關於L的函式z(L)具有很多不錯的性質:分段線性,凹函式,嚴格遞減,(-nC)<0,且z(nC)>0。
根據上面的性質,顯然當確定參量L,便可以檢驗最值L*是否大於小於或等於當前的L。二分搜尋答案對於浮點誤差控制較好,但是效率略低。另一種方法類似於牛頓迭代的Dinkelbach演算法,二分搜尋方法的收斂速度僅僅是線性的,而Dinkelbach的收斂速度卻是超線性的。

Dinkelbach演算法

其本質上是觀察直線:z=cx’-Ldx’
於函式z(L)在L=L’處相切,這裡x’是子問題Q(L’)的最優解。因此,-dx’是z(L)在L’處的斜率。而且很容易看出上面的直線與L軸相交於L=cx’/dx’
Dinkelbach對於分數規劃的演算法,產生了收斂於L*的參量序列,記C=max{max|ci|,1},顯然問題的最優解在區間[-nC,nC]內。

Dinkelbach演算法:
步驟1:設L=L1,使 L*<=L1<=nC
步驟2:解決子問題Q(L)並得到最優解x
步驟3:如果z(L)=0,那麼輸出x並終止;否則,設L=cx/dx跳到步驟2

例:poj3111 K Best

解法:選取k個元素,使得 最大。

double search(double p){  
    for(int i=0;i<n;i++)  
        jw[i].value=jw[i].v-jw[i].w*p;  
	Arrays.sort(jw);  
	double tv=0,tw=0;  
	for(int i=0;i<k;i++){  
        tv+=jw[i].v;  
        tw+=jw[i].w;  	        
    }  
    return tv/tw;  
}  
double ans=1,temp;  
while(true){  
    temp=search(ans);  
    if(Math.abs(ans-temp)<0.001)  
        break;  
    ans=temp;  
}

【0-1分數規劃應用】

1.最優比率生成樹(poj2526 Desert King)

問題:一個帶權完全圖,每條邊都有自己的花費值cost[i]和 長度dis[i],求一個生成樹,使得r=(∑cost[i]*x[i] ) / (∑dis[i]*x[i] )最小。
解法:search時將每條邊邊權設為cost[i][j]-dis[i][j]*p,求最小生成樹時選取的邊既為一組解,不斷迭代。

2.最優比率環:(poj3621 SightSeeing)

問題:有向圖中,每個點有一個權值C(1<=c<=1000),每條邊有權值D(1<=D<=1000),要求找出一個環(沒有重點),環包含的點數要>=2,使得sum{C}/sum{D}最大。
解法:由於此題求解的是存在性問題,不可套用Dinkelbach演算法迭代,因此二分答案求解最大值,對於給定的g如果以<a,b>權重為g*D[b]-C[i]的圖中存在環路,則ans>=g(注意二分double時結束條件right-left<eps,轉移為left=mid、right=mid)。

3.最大密度子圖