题解 [USACO18OPEN] Talent Show
题目描述
题目描述网上有。
具体做法
01分数规划入门题!
考虑我们为每个数设一个 x i x_i xi, x i x_i xi只有 0 , 1 0,1 0,1两种取值。
那么题目要求的式子为:
∑
i
=
1
n
t
i
x
i
w
i
x
i
\sum_{i=1}^{n}{\frac{t_ix_i}{w_ix_i}}
i=1∑nwixitixi
相当于我们要求解每个
x
i
x_i
xi的取值,同时满足
∑
i
=
1
n
w
i
x
i
≥
W
\sum_{i=1}^{n}{w_ix_i} \geq W
∑i=1nwixi≥W。
考虑二分答案 m i d mid mid。
式子变成:
∑
i
=
1
n
t
i
x
i
w
i
x
i
≥
m
i
d
\sum_{i=1}^{n}{\frac{t_ix_i}{w_ix_i}} \geq mid
i=1∑nwixitixi≥mid
移项后变成
∑
i
=
1
n
x
i
(
t
i
−
w
i
m
i
d
)
≥
0
\sum_{i=1}^{n}{x_i(t_i-w_imid)} \ge 0
i=1∑nxi(ti−wimid)≥0
把
t
i
−
w
i
m
i
d
t_i-w_imid
ti−wimid看成
v
a
l
i
val_i
vali,那么就可以做一个简单背包来判断了。
C o d e \mathcal{Code} Code
/*******************************
Author:galaxy yr
LANG:C++
Created Time:2019年10月27日 星期日 21时56分52秒
*******************************/
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct IO{
template<typename T>
IO & operator>>(T&res)
{
T q=1;char ch;
while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q;
res=(ch^48);
while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48);
res*=q;
return *this;
}
}cin;
const int maxn=255;
const double eps=1e-4;
int n,W,w[maxn],t[maxn];
double val[maxn],f[10000];
double ans;
bool check(double mid)
{
for(int i=1;i<=n;i++)
val[i]=t[i]-w[i]*mid;
for(int i=1;i<=2*W;i++) f[i]=-1e9;
f[0]=0;
for(int i=1;i<=n;i++)
{
for(int j=W*2;j>=w[i];j--)
{
f[j]=max(f[j],f[j-w[i]]+val[i]);
if(f[j]>=0 && j>=W)
return 1;
}
}
return 0;
}
int main()
{
//freopen("p4377.in","r",stdin);
//freopen("p4377.out","w",stdout);
cin>>n>>W;
for(int i=1;i<=n;i++)
cin>>w[i]>>t[i];
double l=0,r=1e9,mid;
while((r-l)>eps)
{
mid=(l+r)/2;
if(check(mid))
l=mid,ans=mid;
else
r=mid;
}
int res=(int)(ans*1000);
printf("%d\n",res);
return 0;
}