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;
}
总结:
- 这个题最开始的时候读得太快了,没有看到细节的部分.
- 我以为只需要找到最短路即可,但是这是求的比值.