题意
传送门 POJ 2391
题解
F l o y d − W a r s h a l l Floyd-Warshall Floyd−Warshall 求出任意两点间的最短路,二分所需的最短时间。
每次二分重新建图,设源点、汇点分别为 s , t s,t s,t,当前二分值为 m i d mid mid,每一块土地当前的牛数量为 f i e l d [ i ] field[i] field[i],每一块土地上的避难处可容纳的牛的数量为 s h e l t e r [ i ] shelter[i] shelter[i],则从 s s s 向每一块土地(标记为 1 − F 1-F 1−F)连一条容量为 f i e l d [ i ] field[i] field[i] 的边,从 t t t 向每一个避难处(标记为 F + 1 − F × 2 F+1-F\times 2 F+1−F×2)连一条容量为 s h e l t e r [ i ] shelter[i] shelter[i] 的边,对于土地 i i i 与土地 j j j 的最短路小于等于 m i d mid mid 的情况,从土地 i i i 向土地 j j j 上的避难所连一条容量为 i n f inf inf 的边。
若最大流为牛的总数,则收缩上界;若所有边都在图中而最大流小于牛的总数,则判无解;对于避难处容量小于牛的总数的情况,可直接判无解。
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define INF 0x3f3f3f3f
#define MAX_V 410
typedef int capType;
struct edge
{
int to, rev;
capType cap;
edge(int to, int rev, capType cap) : to(to), rev(rev), cap(cap) {}
};
int V;
vector<edge> G[MAX_V];
int level[MAX_V], iter[MAX_V];
void add_edge(int from, int to, capType cap)
{
G[from].push_back(edge(to, G[to].size(), cap));
G[to].push_back(edge(from, G[from].size() - 1, 0));
}
void bfs(int s)
{
memset(level, -1, sizeof(level));
queue<int> que;
level[s] = 0;
que.push(s);
while (!que.empty())
{
int v = que.front();
que.pop();
for (int i = 0; i < G[v].size(); i++)
{
edge &e = G[v][i];
if (e.cap > 0 && level[e.to] < 0)
{
level[e.to] = level[v] + 1;
que.push(e.to);
}
}
}
}
capType dfs(int v, int t, capType f)
{
if (v == t) return f;
for (int &i = iter[v]; i < G[v].size(); i++)
{
edge &e = G[v][i];
if (e.cap > 0 && level[v] < level[e.to])
{
capType d = dfs(e.to, t, min(f, e.cap));
if (d > 0)
{
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
capType max_flow(int s, int t)
{
capType flow = 0;
for (;;)
{
bfs(s);
if (level[t] < 0)
return flow;
memset(iter, 0, sizeof(iter));
capType f;
while ((f = dfs(s, t, INF)) > 0)
{
flow += f;
}
}
}
void clear_graph()
{
for (int v = 0; v < V; v++) G[v].clear();
}
typedef long long ll;
#define maxf 205
#define inf 0x3f3f3f3f3f3f3f3f
int F, P, nf, ns;
int field[maxf], shelter[maxf];
ll maxd, dp[maxf][maxf];
void floyd()
{
maxd = 0;
for (int k = 1; k <= F; k++)
{
for (int i = 1; i <= F; i++)
{
for (int j = 1; j <= F; j++)
{
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
}
}
}
for (int i = 1; i <= F; i++)
{
for (int j = 1; j <= F; j++)
{
if (dp[i][j] != inf) maxd = max(maxd, dp[i][j]);
}
}
}
void solve()
{
int s = 0, t = F * 2 + 1;
V = t + 1;
floyd();
ll lb = -1, ub = maxd + 1;
while (ub - lb > 1)
{
ll mid = (ub + lb) >> 1;
clear_graph();
for (int i = 1; i <= F; i++)
{
add_edge(i, F + i, INF);
for (int j = i + 1; j <= F; j++)
{
if (dp[i][j] > mid) continue;
add_edge(i, F + j, INF);
add_edge(j, F + i, INF);
}
}
for (int i = 1; i <= F; i++)
{
add_edge(s, i, field[i]);
add_edge(F + i, t, shelter[i]);
}
if (max_flow(s, t) == nf) ub = mid;
else lb = mid;
}
printf("%lld\n", ub > maxd ? -1 : ub);
}
int main()
{
while (~scanf("%d%d", &F, &P))
{
memset(dp, 0x3f, sizeof(dp));
nf = 0, ns = 0;
for (int i = 1; i <= F; i++)
{
dp[i][i] = 0;
scanf("%d%d", field + i, shelter + i);
nf += field[i], ns += shelter[i];
}
for (int i = 0; i < P; i++)
{
int u, v, d;
scanf("%d%d%d", &u, &v, &d);
dp[u][v] = dp[v][u] = min(d, dp[u][v]);
}
if (nf > ns)
{
puts("-1");
continue;
}
solve();
}
return 0;
}