背包问题 V3( 分数规划入门题)
个物品的体积为 ( 为整数),与之相对应的价值为 ( 为整数),从中选出 件物品(),使得单位体积的价值最大。
对于题目中的单位体积的价值可以理解为:
其中 的选取同时会影响到分子和分母的大小,从而影响最终答案,因此无法进行贪心选择。
通过 分数规划解决问题,将原本的问题进行转换。
首先令答案为 ,那么有 。
将其修改得到其变式为
那么就是说这个答案 是一定存在一个方案使得上述式子为 。
由此,假如一个 使得上述公式的最大值大于 的话,就表示还有更优的答案 ,相反同理。
那么就可以考虑二分答案,将每个物品的权值看作 。
这时候我们只需要选择 个数,判断其最大值是否大于 即可,此时可以选择贪心求解。
//
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps = 1e - 5;
double l, r, d[100100], tmp;
int a[100100], b[100100], tmpk[100100];
int tmpp, tmpq, n, k, fq, fp, fk;
int gcd(int a,int b) {
while(b^=a^=b^=a%=b);
return a;
}
bool check(double x) {
tmp = 0.00; tmpp = tmpq = 0;
for (int i = 1; i <= n; i ++ ) {
d[i] = 1.00 * a[i] - 1.00 * b[i] * x;
tmpk[i] = i;
}
sort(tmpk + 1, tmpk + 1 + n, [](int x,int y) {
return d[x] > d[y];
});
for (int i = 1; i <= k; i ++ ) {
tmp += d[tmpk[i]]; tmpq += a[tmpk[i]]; tmpp += b[tmpk[i]];
}
return tmp >= eps;
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i ++ ) {
scanf("%d%d", &b[i], &a[i]);
}
l = 0.00; r = 100000.00;
while (r - l > eps) {
double mid = (l + r) / 2.00;
if (check(mid)) {
l = mid;
fq = tmpq; fp = tmpp;
}
else r = mid;
}
fk = gcd(fq, fp);
printf("%d/%d", fq / fk, fp / fk);
return 0;
}
在判断二分的答案是否合法的时候,有时候需要选择不只是贪心的其他方法,例如:动规等。
同样的是一道入门题:Dropping tests
涉及到树上问题的 规划:规划
分类:
【题解】
, 【冻柜】01分数规划
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】