分数考虑分数规划
∑
t
i
∑
w
i
≥
m
i
d
⇒
∑
(
t
i
−
w
i
×
m
i
d
)
≥
0
\begin{aligned} &\frac{\sum t_i}{\sum w_i}\ge mid\\ \Rightarrow&\sum (t_i-w_i\times mid)\ge0 \end{aligned}
⇒∑wi∑ti≥mid∑(ti−wi×mid)≥0
转化成背包:
花费
w
i
w_i
wi,价值
t
i
−
w
i
×
m
i
d
t_i-w_i\times mid
ti−wi×mid和要
>
0
>0
>0
O ( n 2 log n ) O(n^2\log n) O(n2logn)
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e3+5,INF=1e9;
const double eps=1e-9;
int n,W,w[N],t[N];
double v[N],f[N];
bool check(double mid){
for(int i=1;i<=n;++i)
v[i]=(double)t[i]-w[i]*mid;
for(int i=1;i<=W;++i)
f[i]=-INF;
for(int j=1;j<=n;++j)
for(int i=W;i>=0;--i){
if(i+w[j]>=W) f[W]=max(f[W],f[i]+v[j]);
else f[i+w[j]]=max(f[i+w[j]],f[i]+v[j]);
}
// cout<<mid<<endl;
// for(int i=1;i<=n;++i) cout<<v[i]<<" ";cout<<endl;
// for(int i=1;i<=n;++i) cout<<f[i]<<" ";cout<<endl;
return f[W]>=0;
}
int main(){
n=in,W=in;
for(int i=1;i<=n;++i)
w[i]=in,t[i]=in;
double l=0,r=INF;
while(r-l>eps){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%d\n",(int)floor(l*1000));
return 0;
}