【总结】01分数规划

定义

我们给定两个数组,\(a_i\) 表示 \(i\) 的价值,\(b_i\)表示选取 \(i\) 的代价。如果选取 \(i\),定义 \(x_i = 1\) 否则 \(x_i = 0\)。每个物品只有选和不选的两种方案,求一个选择的方案使得 \(R = \frac{\sum (a_i \cdot x_i)}{\sum(b_i \cdot x_i)}\),也就是选择物品的总收益除以总代价最大或者最小。

01分数规划问题主要包含以下几个问题:

  • 一般的01分数规划
  • 最优比率生成树
  • 最优比率环

01分数规划

\(F(L) = \sum(a_i \cdot x_i) - L \cdot \sum(b_i \cdot x_i)\)

可以化简得到

\(F(L) = \sum(x_i \cdot (a_i - L \cdot b_i))\)

再用 \(d_i\) 替代 \(a_i - L \cdot b_i\)

又可以得到 \(F(L) = \sum(x_i \cdot d_i)\)

而我们的最优解 \(R\), 就可以通过二分得到

例题

01 分数规划

这是一道板子题

我们之前已经得到了

\[F(L) = \sum(x_i \cdot (a_i - L \cdot b_i)) \]

我们可以二分答案,二分出的 \(mid\) 就是函数中的 \(L\), 我们就可以得到 \(d_i\), 由于恰好有 \(K\)\(x_i\)\(1\),由于我们要让 \(F(L) \geq 0\) 所以我们取 \(d_i\) 的前 \(k\) 大的值。

核心代码如下

bool cmp(double x, double y) {
    return x > y;
}
bool check(double m) {
    for (int i = 1; i <= n; i++)
        d[i] = 1.0 * a[i] - m * b[i];
    sort(d + 1, d + n + 1, cmp);
    double sum = 0;
    for (int i = 1; i <= k; i++)
        sum += d[i];
    return sum >= 0; 
}
while (r - l >= eps) {
double mid = (l + r) / 2;
    if (check(mid))
        l = mid;
    else
        r = mid;
}

背包问题 V3

posted @ 2022-07-25 21:37  zhou_ziyi  阅读(320)  评论(0)    收藏  举报