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);
评论区(暂无评论)