Gasoline Gym - 101908G(网络流+二分答案)

After the end of the truck drivers’ strike, you and the rest of Nlogônia logistics specialists now have the task of planning the refueling of the gas stations in the city. For this, we collected information on stocks of R refineries and about the demands of P gas stations. In addition, there are contractual restrictions that some refineries cannot supply some gas stations; When a refinery can provide a station, the shorter route to transport fuel from one place to another is known.

The experts’ task is to minimize the time all stations are supplied, satisfying their demands. The refineries have a sufficiently large amount of trucks, so that you can assume that each truck will need to make only one trip from a refinery to a gas station. The capacity of each truck is greater than the demand of any gas station, but it may be necessary to use more than one refinery.

Input
The first line of the input contains three integers P,R,C, respectively the number of gas stations, the number of refineries and the number of pairs of refineries and gas stations whose time will be given (1≤P,R≤1000; 1≤C≤20000). The second line contains P integers Di (1≤Di≤104), representing the demands in liters of gasoline of the gas stations i=1,2,…,P, in that order. The third line contains R integers Ei (1≤Ei≤104), representing stocks, in liters of gasoline, of refineries i=1,2,…,R, in that order. Finally, the latest C lines describe course times, in minutes, between stations and refineries. Each of these rows contains three integers, I,J,T (1≤I≤P; 1≤J≤R; 1≤T≤106), where I is the ID of a post, J is the ID of a refinery and T is the time in the course of a refinery truck J to I. No pair (J,I) repeats. Not all pairs are informed; If a pair is not informed, contractual restrictions prevents the refinery from supplying the station.

Output
Print an integer that indicates the minimum time in minutes for all stations to be completely filled up. If this is not possible, print −1.

Examples
Input
3 2 5
20 10 10
30 20
1 1 2
2 1 1
2 2 3
3 1 4
3 2 5
Output
4
Input
3 2 5
20 10 10
25 30
1 1 3
2 1 1
2 2 4
3 1 2
3 2 5
Output
5
Input
4 3 9
10 10 10 20
10 15 30
1 1 1
1 2 1
2 1 3
2 2 2
3 1 10
3 2 10
4 1 1
4 2 2
4 3 30
Output
-1
Input
1 2 2
40
30 10
1 1 100
1 2 200
Output
200

二分答案,只建 小于等于答案 的边

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
#include<algorithm>
#include<map>
#define MS(x) memset(x,0,sizeof(x));
#define MS1(x) memset(x,-1,sizeof(x));
using namespace std;
const int MAXN =1e5+5;//点数
const int MAXM =1e6+5;//边数必须得是给定边数的两倍 因为还有反向边
const int maxN =1e5+5;//点数
const int maxM =1e6+5;//边数必须得是给定边数的两倍 因为还有反向边
const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f;

class Graph {
//先Graph G 生成一个类
//然后G.init(n) n是点的个数
//然后addedge加边
//记得设置源点汇点 set_st(start,end);
//最后直接跑Dinic() 返回的就是最大流
	private:
		int s, t;//源点和汇点
		int n;//点的个数
		int cnt;//前向星
		int Head[maxN];//每个点最后一条边的编号
		int Next[maxM];//指向对应点的前一条边
		int W[maxM];//每一条边的残量
		int V[maxM];//每一条边指向的点
		int Depth[maxN];//分层图的深度
		int cur[maxN];//cur就是记录当前点u循环到了哪一条边
	public:
		void init(int n) { //源点 汇点 点的个数
			cnt = -1;
			memset(Head, -1, sizeof(Head));
			memset(Next, -1, sizeof(Next));
			this->n = n;
		}
		void set_st(int source,int terminal) { //设置源点 汇点
			s = source;
			t = terminal;
		}
		void _Add(int u, int v, int w) { //前向星
			cnt++;
			Next[cnt] = Head[u];
			Head[u] = cnt;
			V[cnt] = v;
			W[cnt] = w;
		}
		void Add_Edge(int u, int v, int w) { //前向星
			_Add(u, v, w);
			_Add(v, u, 0);//单向边
		}
		int dfs(int u, int flow) { //u是当前节点,flow是当前流量

			if (u == t)//达到汇点 直接返回
				return flow;
			for (int& i = cur[u]; i != -1; i = Next[i]) { //注意这里的&符号,这样i增加的同时也能改变cur[u]的值,达到记录当前弧的目的
				if ((Depth[V[i]] == Depth[u] + 1) && (W[i] != 0)) { //如果满足分层图条件并且参量不为0
					int di = dfs(V[i], min(flow, W[i]));//向下增广
					if (di > 0) { //增广成功
						W[i] -= di;//正向边减
						W[i ^ 1] += di;//反向边加
						return di;//返回流量
					}
				}
			}
			return 0;//增广失败 返回0
		}
		bool bfs() {
			queue<int> Q;
			while (!Q.empty()) Q.pop();
			MS(Depth);
			Depth[s] = 1;//源点的深度为1
			Q.push(s);
			while (!Q.empty()) {
				int u = Q.front();
				Q.pop();
				for (int i = Head[u]; i != -1; i = Next[i])
					if ((Depth[V[i]] == 0) && (W[i] > 0)) { //深度等于0并且残量大于0
						Depth[V[i]] = Depth[u] + 1;//它就是下一层
						Q.push(V[i]);
					}
			}
			if (!Depth[t]) return 0;//如果汇点的深度为0 也就是不存在增广路
			return 1;//汇点深度不为0 存在增广路
		}
		int Dinic() {
			int Ans = 0;//纪录最大流量
			while (bfs()) { //存在增广路
				for (int i = 1; i <= n; i++)//当前弧优化
					cur[i] = Head[i];
				while (int d = dfs(s, inf)) { //源点汇入inf的流量 当还能增广时 一直增加流量
					Ans += d;
				}
			}
			return Ans;//返回流量
		}
} G;
	
	int P,R,C;
	int p[1050];
	int r[1050];
	int c[20050];
	int a[20050];
	int b[20050];/*
	dijkstra D;
	
	Graph G;
	*/
	int sum;
	int solve(int x) {
		int s=R+P+1;
		int t=s+1;
		G.init(t);
		G.set_st(s,t);
		for(int i=1; i<=R; i++) {
			G.Add_Edge(s,i,r[i]);
		}
		for(int i=R+1;i<=P+R;i++)
		{
		G.Add_Edge(i,t,p[i-R]);
		}	
		for(int i=1;i<=C;i++)
		{
			if(c[i]<=x)
			{
				G.Add_Edge(b[i],R+a[i],p[a[i]]);
			}
		}
		
		
		return  G.Dinic()==sum;
	}
	
	int main()
	{
	
	sum=0;
	int ma=-1;
	cin>>P>>R>>C;
	for(int i=1; i<=P; i++) {
		cin>>p[i];
		sum+=p[i];
	}
	for(int i=1; i<=R; i++) {
		cin>>r[i];
	}
	for(int i=1; i<=C; i++) {
		cin>>a[i]>>b[i]>>c[i];
		ma=max(ma,c[i]);
	}
	
	int ans=0x3f3f3f3f;
	int L=0,R=ma;
	while(L<=R) {
		int mid=(L+R)/2;
		if(solve(mid))
		{
			
			R=mid-1;
			ans=min(ans,mid);
		}
		
		else
		{
			L=mid+1;
		}
		
	}
	if(ans<0x3f3f3f3f)
	cout<<ans<<endl;
	else cout<<-1<<endl;
	
	return 0;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值