01分數規劃問題 - 筆記

1、01分數規劃

詳解:https://blog.csdn.net/hzoi_ztx/article/details/54898323
在這裏插入圖片描述
一般會固定 選擇的二元數組的個數(當固定的個數等於頂點數減一時,也就是最小/大比率生成樹的問題了 ),例如:power oj 2881

2、爲什麼不能貪心?

(後面兩個問題都理解了好久 ༼༎ຶᴗ༎ຶ༽
或許可以藉助一個數學問題來理解:兩堆不同價格的商品混合,怎麼定價才能不賺不賠?

定價=\frac {兩堆商品的總質量} {兩堆商品的總價格},而且單價較低的商品佔的比例越大,定價就會越低。

再回到01分數規劃的問題中,比如在下面的三個二元數組中選兩個二元數組,可以發現選1、3兩組比選1、2兩組的結果更優。所以並不能單根據比值大小來選取(佔比也會影響最終結果)。

318040(2×401×40)1.91\frac {3} {1} 、\frac {80} {40}(\frac {2×40} {1×40})、\frac {1.9} {1}

3、爲什麼可以二分解01分數規劃?

感覺博主結合圖形的解釋很容理解了,這裏寫一下自己的理解過程:我們要求 選取二元數組個數爲 kk 時,rr 的最大值(下面的求和均只包含xi=1x_i=1的部分)

r=valueicostir=\frac {\sum value_i} {\sum cost_i}

valueircosti=0{\sum value_i -r* \sum cost_i=0}

我們先做出所有組合對應的f(x)=valueixcostif(x)={\sum value_i -x* \sum cost_i}的圖像,每個圖像的橫截距(零點)就對這個組合對應的 rr 的值,這些圖像最大的橫截距也就是 rr 的最大值 rr^*
在這裏插入圖片描述
在不知道 rr^∗的情況下:

在圖中上任取一條垂直 xx 軸的豎線,
如果存在直線與這條豎線的交點縱座標爲正,那麼最優值一定在當前豎線的右側;
如果所有直線與這條豎線交點縱座標爲負,那麼最優值一定在當前豎線的左側;
如果所有直線與這條豎線交點縱座標非正且存在直線與這條豎線交點縱座標爲0,那麼當前豎線橫座標即爲最優值 rr^∗

如上圖,要判斷存在性或一定性,其實只需判斷最大的 f(7)f(7) 是否大於0,而最大的 f(7)f(7) 就是所有二元數組對應的 valuei7costi{ value_i -7*cost_i} 中前 kk 大的和(任意 kk 個的組合,肯定是前 kk 大加起來結果最大)。

另外通過這個式子 valueixcosti{ value_i -x*cost_i} 或者圖像也可以看出:xx 的值越大前 kk 大的和越小,所以可以用二分求解。

power oj 2881:Luojie學姐想要代碼少出bug,所以決定去女裝,商店裏有n條小裙子每條小裙子的價格和漂亮程度分別爲wi和pi,luojie學姐想要k條小裙子,ta希望你能幫ta選出k條小裙子,使得單位價格的漂亮程度最大。

#include<algorithm>
#include<iostream>
#include<stdio.h>
#include<vector>
#include<string>
#include<cstring>
#include<math.h>
using namespace std;
//#define int long long
const int manx=1e4+10;
const int manx2=1e7+10;
const int mod=1e9+7;
const double inf=1e9+7;

int n,k;
double p[manx],w[manx];
int check(double x)
{
    double a[manx],ans=0;
    for(int i=1;i<=n;i++)
        a[i]=w[i]-x*p[i];
    sort(a+1,a+n+1,[](int x1,int x2){return x1>x2;});
    for(int i=1;i<=k;i++)
        ans+=a[i];
    return ans>=0;
}
int main()
{
    //ios::sync_with_stdio(false);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%lf%lf",&p[i],&w[i]);
    double l=0,r=1e6;
    while(r-l>1e-4)//這裏寫成1e-3還wa了一發
    {
        double mid=(l+r)/2;
        if(check(mid))
            l=mid;
        else r=mid;
    }
    printf("%.2f\n",l);
    return 0;
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章