[USACO18OPEN]Talent Show

Posted a1b3c7d9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[USACO18OPEN]Talent Show相关的知识,希望对你有一定的参考价值。

[USACO18OPEN]Talent Show

有N对数\(\{w_i\}\)\(\{t_i\}\),选出几对数,使\(w_i\)之和大于W,并且使t之和除以w之和乘以1000尽可能大,\(1≤N≤250,1≤W≤1000\)

显然为分数规划,于是写出二分式\(\sum x_i(t_i-w_is)\),现在问题在于如何选出括号里最大的数,并且使它们的\(w_i\)之和大于W,自然为一最优化问题,考虑递推,但是注意到题目很像背包,于是按照01背包的办法就可以求出最优解,注意边界所以要初始化无限小,其他照01分数规划的套路即可。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define exact 0.000001
using namespace std;
int a[251],b[251],n,w;
double c[251],dp[1001];
il bool check(double);
il double dfs(double,double);
template<class free>il free Max(free,free);
int main(){
    int i;scanf("%d%d",&n,&w);
    for(i=1;i<=n;++i)
        scanf("%d%d",&b[i],&a[i]),a[i]*=1000;
    printf("%.0lf",dfs(0,250000)-0.5);
    return 0;
}
template<class free>
il free Max(free a,free b){
    return a>b?a:b;
}
il bool check(double x){
    int i,j;
    for(i=1;i<=w;++i)dp[i]=-1e19;
    for(i=1;i<=n;++i){
        c[i]=a[i]-b[i]*x;
        for(j=w;j>=w-b[i]&&j>=0;--j)
            dp[w]=Max(dp[w],dp[j]+c[i]);
        for(j=w;j>=b[i];--j)
            dp[j]=Max(dp[j-b[i]]+c[i],dp[j]);
    }return dp[w]>exact;
}
il double dfs(double l,double r){
    double mid;
    while(l+exact<r){
        mid=(l+r)/2;
        if(check(mid))l=mid+exact;
        else r=mid-exact;
    }return (l+r)/2;
}

以上是关于[USACO18OPEN]Talent Show的主要内容,如果未能解决你的问题,请参考以下文章

P4377 [USACO18OPEN]Talent Show

[Usaco2018 Open]Talent Show

LG4377 「USACO2018OPEN」Talent Show 线性规划+背包

P4379 [USACO18OPEN]Lemonade Line

4579: [Usaco2016 Open]Closing the Farm

[USACO18OPEN] Multiplayer Moo (并查集+维护并查集技巧)