洛谷P5837 [USACO19DEC] Milk Pumping G

P5837

题目描述

Farmer John 最近为了扩张他的牛奶产业帝国而收购了一个新的农场。这一新的农场通过一个管道网络与附近的小镇相连,FJ 想要找出其中最合适的一组管道,将其购买并用来将牛奶从农场输送到小镇。

这个管道网络可以用 N 个接合点(管道的端点)来描述,将其编号为 1…N。接合点 1 表示 FJ 的农场,接合点 N 表示小镇。有 M 条双向的管道,每条连接了两个接合点。使用第 i 条管道需要 FJ 花费 ci​ 美元购入,可以支持每秒 fi​ 升牛奶的流量。

FJ 想要购买一条管道组成一条单一路径,路径的两端点分别为接合点 1 和 N。这条路径的花费等于路径上所有管道的费用之和。路径上的流量等于路径上所有管道的最小流量(因为这是沿这条路径输送牛奶的瓶颈)。FJ 想要最大化路径流量与路径花费之比。保证存在从 1 到 N之间的路径。

输入格式

输入的第一行包含 N 和 M。以下 M 行每行以四个整数描述一条管道:a 和 b(管道连接的两个不同的接合点),c(管道的花费),以及 f(管道的流量)。花费和流量均为范围 1…1000 之内的正整数。

输出格式

输出 10^6 乘以最优解的值,并向下取整(也就是说,如果这个数本身不是整数,输出小于它的最接近它的整数)。

输入输出样例

输入 #1复制

3 2
2 1 2 4
2 3 5 3

输出 #1复制

428571

说明/提示

在这个例子中,仅由一条路径从 1 到 N。 它的流量为min(3,4)=3,花费为 2+5=7。

数据范围

测试点 2∼5 满足 N,M≤100。

对于 100% 的数据,2≤N≤1000,1≤M≤1000。

供题:Brian Dean

代码: 

#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>//宏定义 
#define int long long
int n,m,l,r;
int dis[1000010];
bool vis[1000010];
vector<pair<int,pair<int,int>>> e[1000010];
bool check(int mid){//dijkstra模板 改动 
	for(int i = 1;i<=n;i++){
		dis[i]=1e18;
		vis[i]=0;
	}
	priority_queue<PII,vector<PII>,greater<PII> > q; 
	q.push({0,1});
	dis[1]=0;
	while(q.size()){
		auto t=q.top();
		q.pop();
		auto now=t.second;
		if(vis[now]) continue;
		vis[now]=1;
		for(auto tt:e[now]){
			auto a=tt.first;
			auto b=tt.second;
			if(b.second>=mid&&dis[a]>dis[now]+b.first){
			//判断经过的所有管子流量是否都大于mid,路径花费是否更小 
				dis[a]=dis[now]+b.first;
				q.push({dis[a],a});//入队 
			}
		} 
	}
	if(dis[n]==1e18) return 0;//如果dis[n]==1e18,说明这个流量情况下不能到达n点 
	else return 1;
}
signed main(){
	cin >> n >> m;
	for(int i = 1;i<=m;i++){
		int a,b,c,f;
		cin >> a >> b >> c >> f;
		l=min(l,f);
		r=max(r,f);
		e[a].push_back({b,{c,f}});
		e[b].push_back({a,{c,f}}); 
	}
	int maxn=-1e18;//初始化为极小值 
	for(int i = l;i<=r;i++){//从管道的最小流量到最大流量遍历求,而不是从1-1000,更少计算 
		if(check(i)){
			int now=(double)i/dis[n]*1e6;
			maxn=max(maxn,now);//得较大值 
		}
	}
	cout << maxn;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值