题目描述
FJ 的牛们非常害怕淋雨,那会使他们瑟瑟发抖。他们打算安装一个下雨报警器,并且安排了一个撤退计划。他们需要计算最少的让所有牛进入雨棚的时间。
牛们在农场的 FF 个田地上吃草。有 PP 条双向路连接着这些田地。路很宽,无限量的牛可以通过。田地上有雨棚,雨棚有一定的容量,牛们可以瞬间从这块田地进入这块田地上的雨棚。
请计算最少的时间,让每只牛都进入雨棚。
输入格式
第 11 行:两个整数 FF 和 PP;
第 22 到 F+1F+1 行:第 i+1i+1 行有两个整数描述第 ii 个田地,第一个表示田地上的牛数,第二个表示田地上的雨棚容量。两个整数都在 00 和 10001000 之间。
第 F+2F+2 到 F+P+1F+P+1 行:每行三个整数描述一条路,分别是起点终点,及通过这条路所需的时间(在 11 和 10^9109 之间)。
输出格式
一个整数,表示最少的时间。如果无法使牛们全部进入雨棚,输出 -1−1。
输入输出样例
输入 #1复制
3 4 7 2 0 4 2 6 1 2 40 3 2 70 2 3 90 1 3 120
输出 #1复制
110
说明/提示
对于 100\%100% 的数据:1\le F\le 2001≤F≤200,1\le P\le 15001≤P≤1500。
上代码:
#include <bits/stdc++.h>
using namespace std;
#define M 100010
#define N 1010
#define ll long long
const ll inf = (ll)1e18; // 一定要够大
template <class T>
inline void read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){
if(c == '-') s = -1;
c = getchar();
}
while(isdigit(c)){
x = x * 10 + (c ^ '0');
c = getchar();
}
a = x * s;
return ;
}
struct node{
int v, next;
ll w;
public:
node(int v = 0, ll w = 0, int next = -1){ // 方便初始化为 -1
this -> v = v;
this -> w = w;
this -> next = next;
return ;
}
inline void clean(){
this -> v = 0;
this -> w = 0;
this -> next = -1;
return ;
}
}t[M << 1];
int f[N];
ll dis[N][N];
int n, m;
int suma = 0, sumb = 0; // 奶牛总数和雨棚总容量
int a[N], b[N];
int s, ht; // 起点和终点
int bian = -1;
inline void add(int u, int v, ll w){
t[++bian] = node(v, w, f[u]), f[u] = bian;
t[++bian] = node(u, 0, f[v]), f[v] = bian; // 反向虚边
return ;
}
struct Max_Flow{ // 最大流
int deth[N];
int cur[N];
bool bfs(){
queue <int> q;
memset(deth, 0, sizeof(deth));
deth[s] = 1;
q.push(s);
while(!q.empty()){
int now = q.front(); q.pop();
for(int i = f[now]; ~i; i = t[i].next){
int v = t[i].v;
if(!deth[v] && t[i].w){
deth[v] = deth[now] + 1;
q.push(v);
}
}
}
return deth[ht] != 0;
}
ll dfs(ll now,ll dist){
if(now == ht || !dist)return dist;
for(int& i = cur[now]; ~i; i = t[i].next){
ll v = t[i].v;
if(deth[v] == deth[now] + 1 && t[i].w != 0){
ll di = dfs(v, min(dist, t[i].w));
if(di > 0){
t[i].w -= di;
t[i^1].w += di;
return di;
}
}
}
return 0;
}
ll Dicnic(){
ll sum = 0;
while(bfs()){
memcpy(cur, f, sizeof(cur));
while(ll temp = dfs(s, inf))
sum += temp;
}
return sum;
}
} T;
inline void clean(){
memset(f, -1, sizeof(f));
for(int i = 1; i <= bian; i++)
t[i].clean();
bian = -1;
return ;
}
bool judge(ll mid, int sum){
clean(); // 记得清空
for(int i = 1; i <= n; i++){
add(s, i, a[i]);
add(i + n, ht, b[i]);
for(int j = 1; j <= n; j++){
if(i == j || dis[i][j] <= mid) // 本身就在这块农田或者距离在当前限制之内
add(i, j + n, inf);
}
}
return T.Dicnic() == sum;
}
int main(){
read(n), read(m);
for(int i = 1; i <= n; i++){
read(a[i]), read(b[i]);
suma += a[i], sumb += b[i]; // 牛的总数, 容量的总数
}
if(suma > sumb){ // 特判,如果根本放不下就直接去世
printf("-1");
return 0;
}
s = n * 2 + 1, ht = n * 2 + 2;
memset(dis, 0x3f, sizeof(dis));
for(int i = 1; i <= m; i++){
ll x, y, w;
read(x), read(y), read(w);
dis[x][y] = dis[y][x] = min(dis[x][y], w);
}
for(int k = 1; k <= n; k++) // Floyd 最短路
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
ll l = 0, r = 0;
ll ans = -1;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i != j) r = max(r, dis[i][j]);
while(l <= r){ // 二分答案
ll mid = l + r >> 1;
if(judge(mid, suma)) ans = mid, r = mid - 1;
else l = mid + 1;
}
printf("%lld\n", ans < inf ? ans : -1);
return 0;
}