P5837 [USACO19DEC]Milk Pumping G

该博客讨论了USACO19DEC比赛中的题目Milk Pumping G,主要涉及图论和算法问题。博主解释了题目的意思,即在给定的图中寻找路径花费与最小流量比值的最大值。他们指出,最开始的错误是仅考虑最短路径,而忽略了最小流量。正确做法是使用堆优化的Dijkstra算法,不断枚举边的流量并在松弛操作前判断,以找到比值最大的路径。最后,博主提醒读者要注意题目细节,因为这不是简单的求最短路问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

P5837 [USACO19DEC]Milk Pumping G

题意

现在n个点m条边连接两个点,每一条边又两个值,一个是这条边的花费,一个是这条边的流量,现在让你求从1-n的路径流量与路径的花费的比值的最大值。

思路

我们先把要求的表示出来: 路径的最小流量 ∑ i = 1 n 路径的花费 \frac{路径的最小流量}{\sum_{i=1}^{n}路径的花费} i=1n路径的花费路径的最小流量观察,实际就是:首先找到路径的最短路,在找到这个最短路上的最小流量即可.首先对于一条最短路,它的最小流量肯定是确定的,要使这个值最大,肯定是让分母最小即可.所以其实就是跑一个最短路,然后找到最小流量即可.
最开始的时候我犯了一个错,我直接找到了所有路径的最小流量,然后直接除,结果wa了,这个最小的流量可能不是你找的最短路中的最小流量.
那么我们直接用堆优化版本的Dijkstra就好了,还有一点就是,我们在跑最短路的时候,是通过松弛来实现的对吧,我上面说错了,我说的是直接找最短路径即可.但是这个题不单单是求最短路,它是要让你找比值最大的,可能有些是最短路径虽然很短,但是它的最小流量与它的比值可能没有那么最短路不一定是最短的,但是比值反而更大,所以这个时候我们要不断的枚举每条路的流量,在松弛之前,判断一下此时这条边的流量是否大于我们枚举的这个流量,满足就添加到堆里面,反之就不添加.
看代码:

#include <bits/stdc++.h>

#define x first
#define y second

using namespace std;

const int N = 2e3 + 10, inf = 0x3f3f3f3f;
typedef pair<int, int> PII;

struct node
{
    int to, cost, limit;
    bool operator < (const node &t) const
    {
        return cost > t.cost;
    }
};

int n, m;
vector<node> edge[N];
int dis[N], limit[N];
bool st[N];

int dijkstra(int limit)
{
    priority_queue<node> heap;
    memset(st, 0, sizeof st);
    memset(dis, inf, sizeof dis);

    dis[1] = 0;
    heap.push({1, 0, limit});
    while (!heap.empty())
    {
        int u = heap.top().to; heap.pop();

        if (st[u]) continue;
        st[u] = 1;

        for (auto v : edge[u])
        {
            int j = v.to;
            if (dis[j] > dis[u] + v.cost && v.limit >= limit)
            {
                dis[j] = dis[u] + v.cost;
                heap.push({j, dis[j], limit});
            }
        }
    }

    return dis[n];
}

signed main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> m;
    for (int i = 1; i <= m; i ++)
    {
        int a, b, x; cin >> a >> b >> x >> limit[i];
        edge[a].push_back({b, x, limit[i]});
        edge[b].push_back({a, x, limit[i]});
    }

    int ans = 0;
    for (int i = 1; i <= m; i ++)
        ans = max(ans, limit[i] * int(1e6) / dijkstra(limit[i]));

    cout << ans << endl;

    return 0;
}

总结:

  1. 这个题最开始的时候读得太快了,没有看到细节的部分.
  2. 我以为只需要找到最短路即可,但是这是求的比值.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值