码迷,mamicode.com
首页 > 其他好文 > 详细

[USACO18OPEN]Talent Show

时间:2019-05-03 14:46:31      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:问题   lse   优化问题   efi   pre   大于   check   gis   main   

[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

标签:问题   lse   优化问题   efi   pre   大于   check   gis   main   

原文地址:https://www.cnblogs.com/a1b3c7d9/p/10804880.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!