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);
posted @ 2025-03-09 13:07  才瓯  阅读(26)  评论(0)    收藏  举报