[Jzoj] 1287. 躲雨

题目描述

农场有 F ( 1 < = F < = 200 ) F(1<=F<=200) 个奶牛吃草的区域,有 P ( 1 < = P < = 1500 ) P(1<=P<=1500) 条路连接一些区域,路是双向的。有些区域有遮雨棚,每个遮雨棚有自己的容量限制

现在要你计算所有牛都能找到地方躲雨最少需要多少时间

题目解析

先用 F l o y d Floyd 求一个多源最短路

二分枚举 a n s ans, 进行连边,距离小于 a n s ans ,则连

接着用最大流跑个二分匹配,拆点后,两点之间容量为 I N F INF

S S 到点的容量为 X i X_i ,点到 T T 的容量为 Y i Y_i

若最大流量等于奶牛的总量,则这个 a n s ans 可行,继续二分 a n s ans

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N = 2100;
const int inf = 0x3f3f3f;

int n, m, tot, st[N << 1], cur[N << 1], a[N], b[N];
long long dis[N][N], l, r, maxx = -1, mid, ans, sum = 0;
int s, t, dep[N << 1], q[N << 2];
struct node
{
	int last, to;
	long long val;
}w[100010];
void add(int u, int v, int ww)
{
	w[++tot].to = v;
	w[tot].val = ww;
	w[tot].last = st[u];
	st[u] = tot;
}
void build(long long k)
{
	tot = -1;
	memset(w, 0, sizeof w);
	memset(st, -1, sizeof st);
	for (int i = 1; i <= n; i++)
	{
		if (a[i])
			add(s, i, a[i]), add(i, s, 0);
		if (b[i])
			add(i + n, t, b[i]), add(t, i + n, 0);
	}
	for (int i = 1; i <= n; i++)
		if (a[i] || b[i])
			for (int j = 1; j <= n; j++)
				if (dis[i][j] <= k && (a[j] || b[j]))
					add(i, j + n, inf), add(j + n, i, 0);
}
bool bfs()
{
    int ll = 0, rr = 1;
    memset(dep, 0, sizeof dep);
    memset(q, 0, sizeof q);
    dep[s] = 1;
    q[rr] = s;
    while (ll != rr)
    {
        int head = q[++ll];
        for (int i = st[head]; i != -1; i = w[i].last)
        {
            if (w[i].val > 0 && !dep[w[i].to])
            {
                dep[w[i].to] = dep[head] + 1;
                q[++rr] = w[i].to;
            }
        }
    }
    if (dep[t] > 0)
        return true;
    return false;
}
long long dfs(int u, long long k)
{
    if (u == t) return k;
    for (int& i = cur[u]; i != -1; i = w[i].last)
    {
        if (dep[w[i].to] == dep[u] + 1 && w[i].val > 0)
        {
            long long p = dfs(w[i].to, min(w[i].val, k));
            if (p > 0)
            {
                w[i].val -= p;
                w[i ^ 1].val += p;
                return p;
            }
        }    
    }
    return 0;
}
long long dicnic()
{
	long long k = 0;
	while (bfs())
	{
		for (int i = 0; i <= t; i++) cur[i] = st[i];
		while (long long p = dfs(s, inf))
			k += p;
	}
	return k;
}
long long find()
{
	l = 0, r = (long long)1e12 * 2, ans = -1;
	while (l <= r)
	{
		mid = (l + r) >> 1;
		build(mid);
		if (sum == dicnic())
			ans = mid, r = mid - 1;
		else
			l = mid + 1;
	}
	return ans;
}
int main()
{
	scanf("%d%d", &n, &m);
	s = 0, t = 2 * n + 1;
	memset(dis, 0x3f, sizeof dis);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d%d", &a[i], &b[i]);
		sum += a[i];
		dis[i][i] = dis[i + n][i + n] =  0;
	}
	for (int i = 1; i <= m; i++)
	{
		int x, y;
		long long z;
		scanf("%d%d%lld", &x, &y, &z);
		if (dis[x][y] > z)
			dis[x][y] = dis[y][x] = z;
		maxx += z;
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			for (int k = 1; k <= n; k++)
				if (dis[i][k] + dis[k][j] < dis[i][j])
					dis[i][j] = dis[j][i] = dis[i][k] + dis[k][j];
	printf("%lld\n", find());
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43909855/article/details/88755791
今日推荐