[算法]01分数规划

https://blog.csdn.net/hzoi_ztx/article/details/54898323
http://www.51nod.com/Challenge/Problem.html#!#problemId=1257
给定n个二元组((value_i, cost_i)),(value_i)是选择此二元组获得的价值(非负),(cost_i)是选择此二元组付出的代价(非负),设(x_i (x_i \in{{0,1}} ))代表第i个二元组的选与不选,最大(小)化下式
r = ∑ v a l u e i ⋅ x i ∑ c o s t i ⋅ x i r = \frac {\sum {value_i · x_i} } {\sum {cost_i · x_i} } r=costixivalueixi
如何解决这个问题呢?化简可以得到
r ⋅ ∑ c o s t i ⋅ x i = ∑ v a l u e i ⋅ x i r · \sum {cost_i · x_i} = \sum {value_i · x_i} rcostixi=valueixi
二分r,选前k个求(value_i – r · cost_i)的和,大于eps说明r还能再大。

struct e{
    int v, c;
    double r;
}a[maxn];
bool cmp(e a, e b){return a.r > b.r;}
int main()
{
    int n, k;
    n = in(); k = in();
    for (int i = 0; i < n; ++i){
        a[i].c = in(); a[i].v = in();
    }
    double l = 0, r = 50001, ans;
    for (int i = 0; i < 32; ++i){
        double m = (l + r) / 2;
        for (int j = 0; j < n; ++j) a[j].r = a[j].v - m * a[j].c;
        sort(a, a + n, cmp);
        double sum = 0;
        for (int j = 0; j < k; ++j) sum += a[j].r;
        if (sum <= eps){
            ans = l;
            r = m;
        }else{
            l = m;
        }
    }
    for (int i = 0; i < n; ++i) a[i].r = a[i].v - ans * a[i].c;
    sort(a, a + n, cmp);
    ll sa = 0, sb = 0;
    for (int i = 0; i < k; ++i){
        sa += a[i].v, sb += a[i].c;
    }
    ll c = gcd(sa, sb);
    sa /= c, sb /= c;
    out(sa); putchar('/'); out(sb);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值