题目描述
Farmer John 最近为了扩张他的牛奶产业帝国而收购了一个新的农场。这一新的农场通过一个管道网络与附近的小镇相连,FJ 想要找出其中最合适的一组管道,将其购买并用来将牛奶从农场输送到小镇。
这个管道网络可以用 $N$ 个接合点(管道的端点)来描述,将其编号为 $1…N$。接合点 $1$ 表示 FJ 的农场,接合点 $N$ 表示小镇。有 $M$ 条双向的管道,每条连接了两个接合点。使用第 $i$ 条管道需要 FJ 花费 $c_i$ 美元购入,可以支持每秒 $f_i$ 升牛奶的流量。
FJ 想要购买一条管道组成一条单一路径,路径的两端点分别为接合点 $1$ 和 $N$。这条路径的花费等于路径上所有管道的费用之和。路径上的流量等于路径上所有管道的最小流量(因为这是沿这条路径输送牛奶的瓶颈)。FJ 想要最大化路径流量与路径花费之比。保证存在从 $1$ 到 $N$之间的路径。
输入格式
输入的第一行包含 $N$ 和 $M$。以下 $M$ 行每行以四个整数描述一条管道:$a$ 和 $b$(管道连接的两个不同的接合点),$c$(管道的花费),以及 $f$(管道的流量)。花费和流量均为范围 $1…1000$ 之内的正整数。
输出格式
输出 $10^6$ 乘以最优解的值,并向下取整(也就是说,如果这个数本身不是整数,输出小于它的最接近它的整数)。
样例数据
输入
3 2 2 1 2 4 2 3 5 3
输出
428571
分析
给定一个无向图,每条边有其代价 $c$ 和限制 $f$。求出一条从 $1$ 到 $n$ 的路径,使得$\frac{min\left \{Flow_i\right \}}{\sum c_i}$ 最大。
即以$c$为边权跑最短路,用$Dijkstra$或$SPFA$均可,为了达到枚举 $f$ 起的限制作用,我们在每次松弛操作之前,要先判断这条边的限制是否大于 $f$。否则不把这条边计算的最短路中,因为它不满足当前限制。
代码
#include <bits/stdc++.h> #define Enter puts("") #define Space putchar(' ') #define MAXN 2000100 #define INF 1e6 using namespace std; typedef long long ll; typedef double Db; inline ll Read() { ll Ans = 0; char Ch = getchar() , Las = ' '; while(!isdigit(Ch)) { Las = Ch; Ch = getchar(); } while(isdigit(Ch)) { Ans = (Ans << 3) + (Ans << 1) + Ch - '0'; Ch = getchar(); } if(Las == '-') Ans = -Ans; return Ans; } inline void Write(ll x) { if(x < 0) { x = -x; putchar('-'); } if(x >= 10) Write(x / 10); putchar(x % 10 + '0'); } struct Edge { int Dis , To , Next , Flow; }E[MAXN]; int Head[MAXN] , Dis[MAXN] , Count; bool Visit[MAXN]; int n , m; int MAX; inline void Add_Edge(int u , int v , int d , int Flow) { E[++Count].Dis = d; E[Count].To = v; E[Count].Next = Head[u]; E[Count].Flow = Flow; Head[u] = Count; } struct Node { int Dis , Position; bool operator < (const Node &x) const { return x.Dis < Dis; } Node(int Dis , int Position):Dis(Dis) , Position(Position){} }; priority_queue <Node> Q; inline void Dijkstra() { for(int x = 1; x <= 1000; x++) { for(int j = 1; j <= n; j++) { Dis[j] = INF; Visit[j] = false; } Dis[1] = 0; Q.push(Node(0 , 1)); while(!Q.empty()) { Node Temp = Q.top(); Q.pop(); int u = Temp.Position; if(Visit[u]) continue; Visit[u] = true; for(int i = Head[u]; i; i = E[i].Next) { if(E[i].Flow < x) continue; int v = E[i].To; if(Dis[u] + E[i].Dis < Dis[v]) { Dis[v] = Dis[u] + E[i].Dis; if(!Visit[v]) Q.push(Node(Dis[v] , v)); } } } if(Dis[n] != INF) MAX = max(MAX , x * 1000000 / Dis[n]); } } int main() { n = Read() , m = Read(); for(int i = 1; i <= m ; i++) { int u = Read() , v = Read() , d = Read() , Flow = Read(); Add_Edge(u , v , d , Flow); Add_Edge(v , u , d , Flow); } Dijkstra(); Write(MAX); return 0; }