P5837 [USACO19DEC]Milk Pumping G

题目描述

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;
}

 

上一篇:P5838 [USACO19DEC]Milk Visits G


下一篇:js中数组常用的API(二)之迭代函数