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