[USACO18OPEN]Talent Show
Posted a1b3c7d9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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
LG4377 「USACO2018OPEN」Talent Show 线性规划+背包
P4379 [USACO18OPEN]Lemonade Line