分数规划
分数规划
给一堆物品,有两属性\(a[i]\),\(b[i]\)求一个选择数组使得下式最大化:
\[\frac{\sum w[i]*a[i]}{\sum w[i]*b[i]}(其中w[i]\in \{0,1\})
\]
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define endl '\n'
const int MAXN = 1e5;
const double eps = 1e-6;
double a[MAXN + 10];
double b[MAXN + 10];
int n;
void clean()
{
}
bool check(double x)
{
for (int i = 1; i <= n; ++i)
if (a[i] - b[i] * x > 0)
return 1;
return 0;
}
void solve()
{
// max{sum{a}/sum{b}}
clean();
scanf("%d", &n);
double l = 0, r = 0, mid;
for (int i = 1; i <= n; ++i)
scanf("%lf%lf", &a[i], &b[i]),
r += b[i];
while (l + eps < r)
{
mid = (l + r) / 2;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%.6lf\n", l);
}
int main()
{
ios::sync_with_stdio(false);
cout.tie(NULL);
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
例题
洛谷P4377
限定第二维和为W以上
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define endl '\n'
const int MAXN = 1e5;
const double eps = 1e-6;
const double INF = 1e15;
int w[MAXN + 10];
int t[MAXN + 10];
int n, W;
double dp[1010];
void clean()
{
}
bool check(double x)
{
for (int i = 1; i <= W; ++i)
dp[i] = -INF;
dp[0] = 0;
for (int i = 1; i <= n; ++i)
for (int j = W; j >= 0; --j)
{
if (dp[j] == -INF)
continue;
int tar = min(W, j + w[i]);
dp[tar] = max(dp[j] + (double)t[i] - w[i] * x, dp[tar]);
}
if (dp[W] > 0)
return 1;
return 0;
}
void solve()
{
clean();
scanf("%d%d", &n, &W);
double l = 0, r = 0, mid;
for (int i = 1; i <= n; ++i)
scanf("%d%d", &w[i], &t[i]),
r += t[i];
while (l + eps < r)
{
mid = (l + r) / 2;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%lld\n", (LL)(l * 1000));
}
int main()
{
ios::sync_with_stdio(false);
cout.tie(NULL);
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
其他
求比例最小生成树等
都是基于二分。