Gym101908G、Gasoline (二分+最大流)

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 RR refineries and about the demands of PP 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,CP,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≤10001≤P,R≤1000; 1≤C≤200001≤C≤20000). The second line contains PP integers DiDi (1≤Di≤1041≤Di≤104), representing the demands in liters of gasoline of the gas stations i=1,2,…,Pi=1,2,…,P, in that order. The third line contains RRintegers EiEi (1≤Ei≤1041≤Ei≤104), representing stocks, in liters of gasoline, of refineries i=1,2,…,Ri=1,2,…,R, in that order. Finally, the latest CC lines describe course times, in minutes, between stations and refineries. Each of these rows contains three integers, I,J,TI,J,T (1≤I≤P1≤I≤P; 1≤J≤R1≤J≤R; 1≤T≤1061≤T≤106), where II is the ID of a post, JJ is the ID of a refinery and TT is the time in the course of a refinery truck JJ to II. No pair (J,I)(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<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<unordered_set>
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long LL;


int n, m, K;
int a[1005], b[1005];
int u[20005], v[20005], w[20005];
LL suma, sumb;

const int maxn = 3005;
struct Edge
{
	Edge() {}
	Edge(int from, int to, int cap, int flow) :from(from), to(to), cap(cap), flow(flow) {}
	int from, to, cap, flow;
};

struct Dinic
{
	int n, m, s, t;            //结点数,边数(包括反向弧),源点与汇点编号
	vector<Edge> edges;     //边表 edges[e]和edges[e^1]互为反向弧
	vector<int> G[maxn];    //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
	bool vis[maxn];         //BFS使用,标记一个节点是否被遍历过
	int d[maxn];            //从起点到i点的距离
	int cur[maxn];          //当前弧下标

	void init(int n)
	{
		this->n = n;
		for (int i = 0; i <= n; i++) G[i].clear();
		edges.clear();
	}

	void AddEdge(int from, int to, int cap)
	{
		edges.push_back(Edge(from, to, cap, 0));
		edges.push_back(Edge(to, from, 0, 0));
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}

	bool BFS()
	{
		memset(vis, 0, sizeof(vis));
		queue<int> Q;//用来保存节点编号的
		Q.push(s);
		d[s] = 0;
		vis[s] = true;
		while (!Q.empty())
		{
			int x = Q.front(); Q.pop();
			for (int i = 0; i<G[x].size(); i++)
			{
				Edge& e = edges[G[x][i]];
				if (!vis[e.to] && e.cap>e.flow)
				{
					vis[e.to] = true;
					d[e.to] = d[x] + 1;
					Q.push(e.to);
				}
			}
		}
		return vis[t];
	}

	int DFS(int x, int a)
	{
		if (x == t || a == 0)return a;
		int flow = 0, f;//flow用来记录从x到t的最小残量
		for (int& i = cur[x]; i<G[x].size(); i++)
		{
			Edge& e = edges[G[x][i]];
			if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0)
			{
				e.flow += f;
				edges[G[x][i] ^ 1].flow -= f;
				flow += f;
				a -= f;
				if (a == 0) break;
			}
		}
		return flow;
	}

	int Maxflow(int s, int t)
	{
		this->s = s, this->t = t;
		int flow = 0;
		while (BFS())
		{
			memset(cur, 0, sizeof(cur));
			flow += DFS(s, inf);
		}
		return flow;
	}
}DC;

bool check(int mid)
{
	DC.init(n + m + 1);
	int vt = n + m + 1;
	for (int i = 1; i <= m; i++)DC.AddEdge(0, i, b[i]);
	for (int i = 1; i <= n; i++)DC.AddEdge(i + m, vt, a[i]);
	for (int i = 1; i <= K; i++)if (w[i] <= mid) DC.AddEdge(v[i], u[i] + m, inf);
	int maxflow =  DC.Maxflow(0, vt);
	if (maxflow == suma)return true;
	else return false;
}
int main()
{
	while (scanf("%d %d %d", &n, &m, &K) != EOF)
	{
		sumb = suma = 0;
		for (int i = 1; i <= n; i++)scanf("%d", &a[i]), suma += a[i];
		for (int i = 1; i <= m; i++)scanf("%d", &b[i]), sumb += b[i];
		for (int i = 1; i <= K; i++)scanf("%d %d %d", &u[i], &v[i], &w[i]);
		if (sumb < suma){printf("-1\n"); continue;}
		int l = 1, r = inf, ans = -1, mid;
		while (l <= r)
		{
			mid = (l + r) >> 1;
			if (check(mid))
			{
				ans = mid;
				r = mid - 1;
			}
			else l = mid + 1;
		}
		printf("%d\n", ans);
	}
}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值