洛谷 P3063 [USACO12DEC]牛奶的路由Milk Routing(dijskra 最短路) 题解

94 篇文章 0 订阅

题目来源:

https://www.luogu.org/problemnew/show/P3063

题目描述:

题目背景

征求翻译。如果你能提供翻译或者题意简述,请直接发讨论,感谢你的贡献。

题目描述

Farmer John's farm has an outdated network of M pipes (1 <= M <= 500) for pumping milk from the barn to his milk storage tank. He wants to remove and update most of these over the next year, but he wants to leave exactly one path worth of pipes intact, so that he can still pump milk from the barn to the storage tank.

The pipe network is described by N junction points (1 <= N <= 500), each of which can serve as the endpoint of a set of pipes. Junction point 1 is the barn, and junction point N is the storage tank. Each of the M bi-directional pipes runs between a pair of junction points, and has an associated latency (the amount of time it takes milk to reach one end of the pipe from the other) and capacity (the amount of milk per unit time that can be pumped through the pipe in steady state). Multiple pipes can connect between the same pair of junction points.

For a path of pipes connecting from the barn to the tank, the latency of the path is the sum of the latencies of the pipes along the path, and the capacity of the path is the minimum of the capacities of the pipes along the path (since this is the "bottleneck" constraining the overall rate at which milk can be pumped through the path). If FJ wants to send a total of X units of milk through a path of pipes with latency L and capacity C, the time this takes is therefore L + X/C.

Given the structure of FJ's pipe network, please help him select a single path from the barn to the storage tank that will allow him to pump X units of milk in a minimum amount of total time.

农民约翰的农场有一套老旧的管网,管网由M条管道(1<=M<=500)构成,用于将牛奶从谷仓运到储奶罐。 他想在明年移除和更新大部分管道,但他想原封不动地保留一条完整的路径,这样他仍然可以把牛奶从谷仓输送到储罐。

管网由N个节点(1<=N<=500)组成,每个点都可以作为一组管道的端点。结点1是谷仓,结点N是储罐。M条双向管道中的每一条都连接一对节点,并且都有一个延迟值(牛奶达到管的另一端的用时)和容量值(单位时间内可以稳定通过管道的牛奶量)。多条管道可以连接同一对节点。

对于一条连接谷仓与储罐的路径,路径的延迟等于沿途所有管道的延迟之和,路径的容量等于沿途管道最小的容量(因为这是制约牛奶运送的“瓶颈”)。如果约翰通过一条延迟为L、容量为C的管道运送X个单位的牛奶,需要的时间为L+X/C。

给出约翰的管网结构,请帮助他选择一条路径,使得他从谷仓到储罐运送X个单位牛奶的总时间最少。

输入输出格式

输入格式:

 

* Line 1: Three space-separated integers: N M X (1 <= X <= 1,000,000).

* Lines 2..1+M: Each line describes a pipe using 4 integers: I J L C. I and J (1 <= I,J <= N) are the junction points at both ends of the pipe. L and C (1 <= L,C <= 1,000,000) give the latency and capacity of the pipe.

第1行:三个空格分隔的整数:N M X(1<=X<=1000000)。

第2行到第M+1行:每一行描述一条管道,有4个整数:I J L C。I和J(1<=I,J<=N)是这条管道连接的两个点。L和C(1<=L,C<=1000000)是这条管道的延迟和容量。

 

输出格式:

 

* Line 1: The minimum amount of time it will take FJ to send milk along a single path, rounded down to the nearest integer.

第1行:约翰沿着一条路径送牛奶花费的最少的时间,向下取整到最近的整数。

 

输入输出样例

输入样例#1: 复制

3 3 15 
1 2 10 3 
3 2 10 2 
1 3 14 1 

输出样例#1: 复制

27 

说明

FJ wants to send 15 units of milk through his pipe network. Pipe #1 connects junction point 1 (the barn) to junction point 2, and has a latency of 10 and a capacity of 3. Pipes #2 and #3 are similarly defined.

The path 1->3 takes 14 + 15/1 = 29 units of time. The path 1->2->3 takes 20 + 15/2 = 27.5 units of time, and is therefore optimal.

约翰想要通过管网运送15个单位的牛奶。管道1连接节点1(谷仓)和节点2,延迟为10,容量为3。管道2和管道3也以相似的方式来定义。

路径1->3花费14+15/1=29个单位的时间。路径1->2->3花费20+15/2=27.5个单位的时间,用时最少。

解题思路:

        有n个点,m条边,每一条边有一个延迟和容量,求x容量的物品从1到n的最小花费,每条路径的总花费是所有边延迟之和再加上X/(所有边中的最小的容量)。

        就是用最短路模板跑一遍,dij或者spfa都可以,关键就是要记录下每一条路径的最小容量是多少,再每次松弛的时候就更新最小容量,dis【】就是X/(更新的最小容量)-X/(上一次最小容量),就可以跑模板了。

代码:

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<stack>
#include<vector>
#include<cstdio>
#define ll long long
#define inf 1e9+10
using namespace std;
const int maxn=1e3;
struct newt
{
    int to,next,limit,cost;
}e[maxn*maxn];
int n,cnt,m,vis[maxn],head[maxn],lj[maxn];
double dis[maxn];
priority_queue<pair<double,int> >q;//优先队列优化
void addedge(int u,int v,int cost,int limit)//邻接表存边
{
    e[cnt].to=v;
    e[cnt].limit=limit;
    e[cnt].cost=cost;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
int main()
{

    memset(head,-1,sizeof(head));
    cnt=0;int X;
    scanf("%d%d%d",&n,&m,&X);
    for(int i=1;i<=n;i++)dis[i]=1e9+10,lj[i]=1e9+10;
    for(int i=1;i<=m;i++)
    {
        int  a,b,cost,limit;
        scanf("%d%d%d%d",&a,&b,&cost,&limit);
        addedge(a,b,cost,limit);
        addedge(b,a,cost,limit);
    }
    q.push(make_pair(0,1));
    dis[1]=0;
    while(!q.empty())
    {
        int now=q.top().second;
        q.pop();
        if(vis[now])continue;
        vis[now]=1;
        for(int i=head[now];i!=-1;i=e[i].next)
        {
            int v=e[i].to,limit=e[i].limit,cost=e[i].cost;
            double val;
           // printf("%d %d %d %d\n",now,v,limit,cost);
            if(limit>=lj[now])//判断最小容量是否更新
            {
                val=cost+double(X/lj[now]);
                if(dis[v]>dis[now]+val-double(X/lj[now]))//记得要减掉上一次的容量花费
                dis[v]=dis[now]+val-double(X/lj[now]),lj[v]=min(lj[now],limit),q.push(make_pair(-dis[v],v));
            }
            else
            {
                val=cost+double(X/limit);
                if(dis[v]>dis[now]+val-double(X/lj[now]))
                dis[v]=dis[now]+val-double(X/lj[now]),lj[v]=min(lj[now],limit),q.push(make_pair(-dis[v],v));
            }
        }
    }
    //for(int i=1;i<=n;i++)printf("%d ",lj[i]);
    int ans=int(dis[n]);//向下取整
    printf("%d\n",ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值