1 条题解
-
0
自动搬运
来自洛谷,原作者为

ker_xyxyxyx_xxs
最是人间留不住 朱颜辞镜花辞树搬运于
2025-08-24 21:37:18,当前版本为作者最后更新于2021-08-26 19:59:05,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
二分答案 网络流
建图:
1、源点 每块田,边权为牛的数量
2、每个牛棚 汇点,边权为牛棚最多能容纳的牛
3、对中间的边进行二分答案。具体操作如下。
使用 floyd 对两个点之间的最短距离预处理,对最小时间进行二分答案。如果在这个时间内可以从 号田地走向 号牛棚,就连一条边,容量为 ,最终检验最大流是否等于牛的数量即可。
一些易错点:
1、存在重边,邻接矩阵需要加上 。
2、邻接矩阵每个点到自己的距离需要赋值为 。
3、二分需要清空之前的数组。
Code
# include <bits/stdc++.h> using namespace std; # define int long long const int N = 1e6 + 5; const int M = 2e6 + 5; const int inf = 1e18; const int maxn = 200 + 5; typedef struct { int x , y , z , next; }Node; Node edge[M]; int E = 1 , elast[N]; int S , T; void add(int x , int y , int z) { E ++ , edge[E].x = x , edge[E].y = y , edge[E].z = z , edge[E].next = elast[x] , elast[x] = E; } int dis[N] , cnt[N]; void bfs(int start) { queue<int> q; q.push(start); dis[start] = 0; cnt[S] = 1; while (!q.empty()) { int cur = q.front(); q.pop(); for (int i = elast[cur] ; i ; i = edge[i].next) { int v = edge[i].y; if (dis[v] != -1) continue; dis[v] = dis[cur] + 1; q.push(v); cnt[dis[v]] ++; } } } int cur[N]; int dfs(int u , int flow) { if (u == T) return flow; int delta = 0; for (int i = cur[u] ; i ; i = edge[i].next) { cur[u] = i; int v = edge[i].y; if (edge[i].z > 0 && dis[u] == dis[v] + 1) { int temp = dfs(v , min(flow - delta , edge[i].z)); edge[i].z -= temp; edge[i ^ 1].z += temp; delta += temp; if (delta == flow) return delta; } } if (dis[S] >= T + 1) return delta; cur[u] = elast[u]; if (-- cnt[dis[u]] == 0) dis[S] = T + 1; cnt[++ dis[u]] ++; return delta; } int Isap() { int ans = 0; memset(cnt , 0 , sizeof cnt); memset(dis , -1 , sizeof dis); bfs(T); for (int i = 0 ; i <= T ; i ++) { cur[i] = elast[i]; } while (dis[S] < T + 1) ans += dfs(S , inf); return ans; } int n , m; int a[N] , b[N] , Dis[maxn][maxn]; void rebuild(int maxv) { for (int i = 1 ; i <= n ; i ++) { add(S , i , a[i]) , add(i , S , 0); add(n + i , T , b[i]) , add(T , n + i , 0); for (int j = 1 ; j <= n ; j ++) { if (Dis[i][j] <= maxv) add(i , n + j , inf) , add(n + j , i , 0); } } } void init() { memset(elast , 0 , sizeof elast); E = 1; } bool check(int cnt) { if (Isap() == cnt) return true; else return false; } int Cnt = 0; signed main() { cin >> n >> m; for (int i = 1 ; i <= n ; i ++) { cin >> a[i] >> b[i]; Cnt += a[i]; } memset(Dis , 0x3f , sizeof Dis); for (int i = 1 ; i <= n ; i ++) Dis[i][i] = 0; for (int i = 1 ; i <= m ; i ++) { int x , y , z; cin >> x >> y >> z; Dis[x][y] = min(Dis[x][y] , z); Dis[y][x] = min(Dis[y][x] , z); } for (int k = 1 ; k <= n ; k ++) { 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]); } } } S = 0 , T = n << 1 | 1; int l = 0 , r = inf; int ans = 0; while (l <= r) { int mid = (l + r) >> 1; init(); rebuild(mid); bool flag = check(Cnt); if (!flag) l = mid + 1; else r = mid - 1 , ans = mid; } if (ans == 0) cout << "-1" << endl; else cout << ans << endl; return 0; }
- 1
信息
- ID
- 1430
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者