spfa + 二分
题目
01分数规划
设
a
n
s
ans
ans 为 最大值
求:
∑
i
=
1
k
f
[
i
]
∑
i
=
1
k
t
[
i
]
≤
a
n
s
\frac {\sum ^ k _ {i = 1} f[i] } {\sum ^ k _ {i = 1} t[i]} \leq ans
∑i=1kt[i]∑i=1kf[i]≤ans
等价于:
∑
i
=
1
k
f
[
i
]
−
t
[
i
]
∗
a
n
s
≤
0
\sum ^ k _ {i = 1} f[i] - t[i] * ans \leq 0
i=1∑kf[i]−t[i]∗ans≤0
则:
∑
i
=
1
k
t
[
i
]
∗
a
n
s
−
f
[
i
]
≥
0
\sum ^ k _ {i = 1} t[i]*ans - f[i] \geq 0
i=1∑kt[i]∗ans−f[i]≥0
二分ans 判负环是否存在
如果 存在,那么证明原式成立 范围缩小到
[
a
n
s
,
r
]
[ans, r]
[ans,r]
如果 不存在, 那么证明原生不对 范围缩小到
[
l
,
a
n
s
]
[l, ans]
[l,ans]
#include <bits/stdc++.h>
const int N = 1111, M = 1e4 + 111;
using namespace std;
int n, m, idx, h[N], v[N], cnt[N];
double f[N], d[N];
struct E {
int v, n, w;
} g[M];
void add (int a, int b, int c) {
g[idx].v = b; g[idx].n = h[a];
g[idx].w = c; h[a] = idx ++;
}
bool spfa (double val) {
queue<int> que;
for (int i = 1; i <= n; ++ i)
que.push(i), v[i] = 1, d[i] = cnt[i] = 0;
while (que.size()) {
auto t = que.front();
que.pop();
v[t] = 0;
for (int i = h[t]; i; i = g[i].n) {
int j = g[i].v;
double w = g[i].w * val - f[t] + d[t];
if (d[j] > w) {
d[j] = w;
cnt[j] = cnt[t] + 1;
if (cnt[j] >= n) return true;
if (!v[j]) que.push(j), v[j] = 1;
}
}
}
return false;
}
int main() {
idx = 1;
cin >> n >> m;
for (int i = 1; i <= n; ++ i) cin >> f[i];
for (int i = 1; i <= m; ++ i) {
int a, b, c;
cin >> a >> b >> c;
add (a, b, c);
}
double l = 1, r = 1000;
for (int i = 1; i <= 50; ++ i) {
double mid = (l + r) / 2;
if (spfa(mid)) l = mid;
else r = mid;
}
printf ("%.2lf\n", l);
return 0;
}
该博客介绍了如何运用SPFA(Shortest Path Faster Algorithm)最短路径算法结合二分查找来解决01分数规划问题。通过设定最大值变量ans,并转换约束条件,判断在ans值下是否存在负环,从而逐步缩小区间,最终找到满足条件的最大值。代码中展示了具体的实现过程,包括边的添加、SPFA算法的定义以及主函数的运行。
209

被折叠的 条评论
为什么被折叠?



