01分数规划
01分数规划
这是一类常见的问题,通常需要求解的是一个分数表达式的极大值,例如
\[\frac{\sum_i^j w}{\sum_i^j t}
\]
可以采取二分的方式进行约算,设 \(x\) 满足
\[\frac{\sum_i^j w}{\sum_i^j t}\ge x
\]
不等式转化为
\[\sum_i^j w-x*\sum_i^j t\ge 0
\]
后续采取贪心或者动态规划的方式,确定满足题意的最大的 \(x\)
贪心例:
给定 \(n,k\) 数组 \(a,b\) 都含有 \(n\) 个元素,满足 \(a_i\le b_i\) ,可以不选 \(k\) 对元素,求满足题意的下列表达式的最大值
\[ans=max\left[ \frac{\sum a}{\sum b} \right]
\]
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++) cin>>b[i];
double l=L,r=R;//根据条件得
while (r-l>0.0001){//精度
double mid=(l+r)/2;
if (judge(mid))
l=mid;
else
r=mid;
}
整理出表达式为
\[\sum a-ans*\sum b \ge 0
\]
二分答案 \(ans\) ,judge 函数内判断是否满足不等式,记 \(c_i=a_i-x*b_i\)
bool judge(double x){
double c[1010],sum=0;
for (int i=1;i<=n;i++) c[i]=a[i]-x*b[i];//计算分项
sort(c+1,c+1+n);//从小到大排序
for (int i=k+1;i<=n;i++) sum+=c[i];//贪心选取
return sum>=0;
}
感性考虑这样一个问题,从一个从大到小排序的数列中选取 \(x\) 个元素使得它们的平均值最大,显然,一定是选前 \(x\) 个元素,且 $x $ 越小,它们的平均值越大
所以对这道题而言,我们选取的 \(c\) 中的元素越少越好,最多能不选 \(k\) 个,那么从大到小选 \(n-k\) 个元素一定最优
动态规划例:
给定数组 \(a,b\) 都含有 \(n\) 个元素,以及限制 \(W\) ,选中的 \(a_i,b_i\) 中 \(\sum b\) 必须满足大于 \(W\) 的限制,求
\[ans=max\left[ \frac{\sum a}{\sum b} \right]
\]
double l=L,r=R;
while (r-l>0.00001){
double mid=(l+r)/2;
if (judge(mid))
l=mid;
else
r=mid;
}
二分的操作前面已经说明,变化在于 judge 函数的实现
bool judge(double x){
for (int j=1;j<=W;j++)
dp[j]=-1e9;
for (int i=1;i<=n;i++){
for (int j=W;j>=0;j--){
int k=min(j+w[i],W);
dp[k]=max(dp[k],dp[j]+t[i]-x*w[i]);
}
}
if (dp[W]>=0) return 1;
else return 0;
}
与 01背包问题类似,经过公式变形后,每件物品的重量为 \(b_i\) ,价值为 \(a_i-x*b_i\),背包的总容量为 \(W\)
选 \(k\) 件物品的重量要么小于 \(W\) 要么大于等于 \(W\) ,所以就可以将大于等于 \(W\) 的状态统一到 \(W\) 上来规划,节约时间
int k=min(j+w[i],W);

浙公网安备 33010602011771号