观光奶牛 spfa

该博客介绍了如何运用SPFA(Shortest Path Faster Algorithm)最短路径算法结合二分查找来解决01分数规划问题。通过设定最大值变量ans,并转换约束条件,判断在ans值下是否存在负环,从而逐步缩小区间,最终找到满足条件的最大值。代码中展示了具体的实现过程,包括边的添加、SPFA算法的定义以及主函数的运行。

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=1kf[i]t[i]ans0
则: ∑ i = 1 k t [ i ] ∗ a n s − f [ i ] ≥ 0 \sum ^ k _ {i = 1} t[i]*ans - f[i] \geq 0 i=1kt[i]ansf[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;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值