AcWing361. 观光奶牛 题解 二分(分数规划)+SPFA判负环

题目链接:https://www.acwing.com/problem/content/363/

解题思路:

首先,假设 fiti>x

(fiti×x)>0

(ti×xfi)<0

也就是说,如果原图中第 i 条边从节点 a 连向 b,边权为 ti,则新图中从 ab 连一条边权为 ti×xfb 的边。

并判断图中是否存在负环,如果存在负环,则比例至少大于 x

可以发现可以通过 二分答案 得到最大的比例。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5, maxm = 5e3 + 5;
int n, m, f[maxn], num[maxn];
double dis[maxn];
bool ins[maxn];
struct Edge {
    int v;
    double w;
};
vector<Edge> g[maxn];
int a[maxm], b[maxm], t[maxm];

void init(double x) {
    for (int i = 1; i <= n; i++)
        g[i].clear(), num[i] = dis[i] = 0;
    for (int i = 0; i < m; i++)
        g[ a[i] ].push_back({ b[i], t[i] * x - f[b[i]] });
}

bool spfa() {
    stack<int> stk;
    for (int i = 1; i <= n; i++) {
        ins[i] = true;
        stk.push(i);
    }
    while (!stk.empty()) {
        int u = stk.top();
        stk.pop();
        ins[u] = false;
        for (auto &[v, w] : g[u]) {
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!ins[v]) {
                    if (++num[v] >= n + 1)
                        return false;
                    ins[v] = true;
                    stk.push(v);
                }
            }
        }
    }
    return true;
}

bool check(double x) {
    init(x);
    return spfa();
}

double cal() {
    double l = 0, r = 1e3;
    while (r - l > 1e-3) {
        double mid = (l + r) / 2;
        if (check(mid))
            r = mid;
        else
            l = mid;
    }
    return l;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", f+i);
    for (int i = 0; i < m; i++)
        scanf("%d%d%d", a+i, b+i, t+i);
    printf("%.2lf\n", cal());
    return 0;
}
posted @   quanjun  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示