分数规划

分数规划

给一堆物品,有两属性\(a[i]\),\(b[i]\)求一个选择数组使得下式最大化:

\[\frac{\sum w[i]*a[i]}{\sum w[i]*b[i]}(其中w[i]\in \{0,1\}) \]

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define endl '\n'
const int MAXN = 1e5;
const double eps = 1e-6;
double  a[MAXN + 10];
double b[MAXN + 10];
int n;
void clean()
{
    
}
bool check(double x)
{
    for (int i = 1; i <= n; ++i)
        if (a[i] - b[i] * x > 0)
            return 1;
    return 0;
}
void solve()
{
    // max{sum{a}/sum{b}}
    clean();
    scanf("%d", &n);
    double l = 0, r = 0, mid;
    for (int i = 1; i <= n; ++i)
        scanf("%lf%lf", &a[i], &b[i]),
        r += b[i];
    while (l + eps < r)
    {
        mid = (l + r) / 2;
        if (check(mid))
            l = mid;
        else 
            r = mid;
    }
    printf("%.6lf\n", l);
}
int main()
{
    ios::sync_with_stdio(false);
    cout.tie(NULL);
    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

例题

洛谷P4377
限定第二维和为W以上

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define endl '\n'
const int MAXN = 1e5;
const double eps = 1e-6;
const double INF = 1e15;
int w[MAXN + 10];
int t[MAXN + 10];
int n, W;
double dp[1010];
void clean()
{
    
}
bool check(double x)
{
    for (int i = 1; i <= W; ++i)
        dp[i] = -INF;
    dp[0] = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = W; j >= 0; --j)
        {
            if (dp[j] == -INF)
                continue;
            int tar = min(W, j + w[i]);
            dp[tar] = max(dp[j] + (double)t[i] - w[i] * x, dp[tar]);
        }
    if (dp[W] > 0)
        return 1;
    return 0;
}
void solve()
{
    clean();
    scanf("%d%d", &n, &W);
    double l = 0, r = 0, mid;
    for (int i = 1; i <= n; ++i)
        scanf("%d%d", &w[i], &t[i]),
        r += t[i];
    while (l + eps < r)
    {
        mid = (l + r) / 2;
        if (check(mid))
            l = mid;
        else 
            r = mid;
    }
    printf("%lld\n", (LL)(l * 1000));
}
int main()
{
    ios::sync_with_stdio(false);
    cout.tie(NULL);
    int T = 1;
    // cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

其他

求比例最小生成树等

都是基于二分。

posted @ 2022-11-09 15:54  cacu  阅读(18)  评论(0编辑  收藏  举报