BZOJ5281 [Usaco2018 Open]Talent Show [0/1分数规划, 背包]

T a l e n t   S h o w Talent\ Show Talent Show

题目描述见链接 .


正 解 部 分 \color{red}{正解部分}

0 / 1 0/1 0/1 分数规划,

二分出答案 m i d mid mid, 要满足 ∑ t i ∑ w i ≤ m i d → m i d × ∑ w i − ∑ t i ≥ 0 → ∑ ( m i d × w i − t i ) ≥ 0 \frac{\sum t_i}{\sum w_i} \le mid \rightarrow mid\times \sum w_i - \sum t_i \geq 0 \rightarrow \sum\left( mid\times w_i - t_i\right) \geq 0 witimidmid×witi0(mid×witi)0 .

由于题目有总重量不小于 W W W 的限制, 所以不能直接贪心选,

考虑 背包, 设 F [ i ] F[i] F[i] 表示总重量为 i i i 所能获得的最大值, 由于 W W W 较小, 而 w i w_i wi 比较大,
所以考虑将 F [ x ≥ W ] F[x \geq W] F[xW] 全部存在 F [ W ] F[W] F[W] 中, 做 0 / 1 0/1 0/1 背包 即可 .


实 现 部 分 \color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

const int maxn = 1005;
const double inf = 1e10;
const double eps = 1e-9;

int N;
int W;
int w[maxn];
int t[maxn];

double F[maxn];

bool check(double mid){
        for(reg int i = 1; i <= W; i ++) F[i] = -inf;
        F[0] = 0;
        for(reg int i = 1; i <= N; i ++)
                for(reg int j = W; j >= 0; j --){
                        double &tmp = F[std::min(W, j+w[i])];
                        tmp = std::max(tmp, F[j] + 1.0*t[i] - 1.0*mid*w[i]);
                }
        return F[W] >= 0;
}

int main(){
        scanf("%d%d", &N, &W);
        double l = 0, r = 0;
        for(reg int i = 1; i <= N; i ++) scanf("%d%d", &w[i], &t[i]), r += t[i];
        double Ans = 0;
        while(r-l > eps){
                double mid = (l+r)/2;
                if(check(mid)) Ans = std::max(Ans, mid), l = mid + eps;
                else r = mid - eps;
        }
        printf("%d\n", (int)(Ans*1000));
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值