链接:https://www.luogu.com.cn/problem/P5837
Farmer John 最近为了扩张他的牛奶产业帝国而收购了一个新的农场。这一新的农场通过一个管道网络与附近的小镇相连,FJ 想要找出其中最合适的一组管道,将其购买并用来将牛奶从农场输送到小镇。
这个管道网络可以用
FJ 想要购买一条管道组成一条单一路径,路径的两端点分别为接合点
输入的第一行包含
输出
3 2
2 1 2 4
2 3 5 3
428571
在这个例子中,仅由一条路径从
测试点
对于
供题:Brian Dean
第一眼看到这个题目,以为是最短路板子,心想这题也能评绿。再一看发现这个最短路有两个评价指标,花费和流量。
设
不难发现若直接使用最短路枚举两个条件的最优解极其复杂,固考虑枚举流量
考虑使用 Dijkstra 堆优化为最短路算法,则时间复杂度为
其实这道题也可以不用枚举 加上本人鸽子 ,就不优化了。
总的来说这道题没啥坑点,只要能想到枚举
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <memory.h>
#include <queue>
using namespace std;
const int N = 1e6 + 10;
const int M = 1e6;
const int INF = 0x3f3f3f3f;
int n, m, ans;
int h[N], idx = 0;
int dis[N], vis[N];
struct Edge {
int nxt, v, w, f;
Edge()
{
this->nxt = -1, this->v = -1, this->w = INF, this->f = INF;
}
Edge(int _nxt, int _v, int _w, int _f)
{
this->nxt = _nxt, this->v = _v, this->w = _w, this->f = _f;
}
} edges[N];
struct Node {
int dis, vtx;
Node(int _dis, int _vtx)
{
this->dis = _dis, this->vtx = _vtx;
}
friend bool operator<(Node x, Node y)
{
// 注意这个符号方向,我因为这个卡了好久
return x.dis > y.dis;
}
};
priority_queue<Node> q;
// 邻接表存图
void addEdge(int a, int b, int c, int f)
{
idx++;
edges[idx].v = b, edges[idx].nxt = h[a], edges[idx].w = c, edges[idx].f = f, h[a] = idx;
}
// Dijkstra 板子
void dijkstra(int u, int lim)
{
dis[u] = 0;
q.push(Node(0, u));
while (!q.empty()) {
Node cur = q.top();
q.pop();
int tmp = cur.vtx;
if (vis[tmp])
continue;
vis[tmp] = 1;
int p = h[tmp];
while (p != -1) {
// 当前管道流量过小,忽略
if (edges[p].f < lim) {
// 下面这行也要注意,我一开始没加就死循环了
p = edges[p].nxt;
continue;
}
if (dis[tmp] + edges[p].w < dis[edges[p].v]) {
dis[edges[p].v] = dis[tmp] + edges[p].w;
if (!vis[edges[p].v])
q.push(Node(dis[edges[p].v], edges[p].v));
}
p = edges[p].nxt;
}
}
}
int main()
{
memset(h, -1, sizeof(h));
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int a, b, c, f;
cin >> a >> b >> c >> f;
addEdge(a, b, c, f);
addEdge(b, a, c, f);
}
for (int i = 1; i <= 1000; i++) {
// 别忘了初始化
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dijkstra(1, i);
if (dis[n] != INF) // 判断能否到达 n
ans = max(ans, i * M / dis[n]);
}
cout << ans << endl;
return 0;
}
AC++!