首页 > 其他分享 >网络流(最大流)

网络流(最大流)

时间:2024-02-21 12:22:52浏览次数:25  
标签:cnt 最大 int res ll 网络 MaxN ans

网络流(最大流)

给定一个网络,有源点和汇点,现在要往源点灌水,问每单位时间可以从汇点出多少水,并且每一条边有限流。

P3376【模板】网络最大流

一个几乎没用的东西:FF

思路

我们很显然会有个思路,就是每次 \(DFS\) 搜索,找到一条路径,并且是可以增广的(限流还没达到),那么就增广它,可是如果遇到一条路径走会满流,但分开走就能流出最大流的情况,所以我们需要一个反悔的机会,可以将剩余可以流的水量建一条正向边形成残余网络,已经流的建一条反向边,于是就有了一个反悔的机会。

EK

思路

将 \(DFS\) 改成 \(BFS\) 即可,这样可以保证每次找到的路径是最短的,但是我们在增广的时候需要把路径弄出来,所以我们用一个 \(pre\) 数组来记录上一个结点,这样就可以记录路径了。

code

#include <iostream>
#include <queue>

using namespace std;
using ll = long long;

const int MaxN = 210, MaxM = 2 * 5010;

struct Edge {
  ll v, w, nxt;
} e[MaxM];

ll h[MaxN], ans;
int n, m, s, t, cnt = 1;
bool vis[MaxN];
queue<int> q;
pair<int, int> p[MaxN];

ll G(int x, ll minx = 1e18) {
  if (x == s) {
    return minx;
  }
  ll res = G(p[x].first, min(minx, e[p[x].second].w));
  e[p[x].second ^ 1].w += res;
  e[p[x].second].w -= res;
  return res;
}

void Record(int u, int i) {
  if (vis[e[i].v] || !e[i].w) {
    return;
  }
  vis[e[i].v] = 1;
  p[e[i].v] = {u, i};
  q.push(e[i].v);
}

ll BFS() {
  for (int i = 1; i <= n; i++) {
    vis[i] = 0, p[i] = {0, 0};
  }
  queue<int>().swap(q);
  for (q.push(s), vis[s] = 1; !q.empty(); q.pop()) {
    int u = q.front();    
    if (u == t) {
      return G(t);
    }    
    for (int i = h[u]; ~i; i = e[i].nxt) {
      Record(u, i);
    }
  }
  return -1;
}

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m >> s >> t;
  fill(h + 1, h + n + 1, -1);
  for (ll i = 1, u, v, w; i <= m; i++) {
    cin >> u >> v >> w;
    e[++cnt] = {v, w, h[u]}, h[u] = cnt;     
    e[++cnt] = {u, 0, h[v]}, h[v] = cnt;
  }
  for (ll res; ~(res = BFS()); ans += res) {
  }
  cout << ans << '\n';
  return 0;
}

时间复杂度:\(O(nm^2)\)

Dinic

每次对残余网络进行分层,将非可是分层的边(树上就是横向边)删了,然后找当前图的最大流,及找到增广路径,然后增广,将当前图的最大流并入最终的最大流。

优化

  1. 在 \(DFS\) 途中,每次将当前边,设为当前点第一条边(注意最后你要还原),因为当处理完这条边后,再处理的话,必然会再一条被增广的路径上被卡死。
  2. 在 \(DFS\) 过程中,如果处理完一条边的答案为 \(0\),那我们标记一下,返回过程中就不走这了,同样的要还原。

code

#include <iostream>
#include <queue>

using namespace std;
using ll = long long;

const int MaxN = 210, MaxM = 2 * 5010;

struct IF {
  struct Edge {
    ll v, w, nxt;
  } e[MaxM];

  ll dis[MaxN], h[MaxN], th[MaxN], ans, n, s, t, cnt;
  bool vis[MaxN];
  queue<int> q;

  IF() {
    n = s = t = ans = 0, cnt = 1;
    fill(h, h + MaxN, -1);
    fill(dis, dis + MaxN, 0);
  }

  void Record(int u, int i) {
    if (vis[e[i].v] || !e[i].w) {
      return;
    }
    vis[e[i].v] = 1;
    dis[e[i].v] = dis[u] + 1;
    q.push(e[i].v);
  }

  bool BFS() {
    for (int i = 1; i <= n; i++) {
      vis[i] = 0, th[i] = h[i];
    }
    queue<int>().swap(q);
    for (q.push(s), vis[s] = 1, dis[s] = 1; !q.empty(); q.pop()) {
      int u = q.front();
      if (u == t) {
        continue;
      }
      for (int i = h[u]; ~i; i = e[i].nxt) {
        Record(u, i);
      }
    }
    return vis[t];
  }

  ll DFS(int x, ll f) {
    if (x == t || !f) {
      return f;
    }
    ll res = 0;
    for (int i = th[x]; ~i && f - res > 0; i = e[i].nxt) {
      th[x] = i;
      if (e[i].w && dis[x] + 1 == dis[e[i].v]) {
        ll tmp = DFS(e[i].v, min(f - res, e[i].w));
        if (!tmp) {
          dis[e[i].v] = 1e18;
        }
        res += tmp;
        e[i].w -= tmp;
        e[i ^ 1].w += tmp;
      }
    }
    return res;
  }

  void insert(int u, int v, ll w) {
    e[++cnt] = {v, w, h[u]}, h[u] = cnt;
    e[++cnt] = {u, 0, h[v]}, h[v] = cnt;
  }

  ll Solov() {
    for (; BFS(); ans += DFS(s, 1e18)) {
    }
    return ans;
  }
};

int n, m, s, t;

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m >> s >> t;
  IF ans;
  ans.n = n, ans.s = s, ans.t = t;
  for (ll i = 1, u, v, w; i <= m; i++) {
    cin >> u >> v >> w;
    ans.insert(u, v, w);
  }
  cout << ans.Solov() << '\n';
  return 0;
}

时间复杂度

最差:\(O(n^2m)\)

标签:cnt,最大,int,res,ll,网络,MaxN,ans
From: https://www.cnblogs.com/ybtarr/p/18021748

相关文章

  • Ubuntu在无网络环境下,用离线源apt-get安装软件
    步骤概要如下:1、假设目标安装的是服务器A,需先准备一台正常环境,且操作系统版本与A一致的服务器B;2、用apt-get在服务器B上下载需要安装的包,并用dpkg-scanpackages依赖打包;3、将打好的依赖包传到服务器A上;4、更新服务器A的apt源,并清空apt缓存;5、服务器A上用apt安装软件。 详......
  • k8s排查网络丢包
    网络丢包的定义与现象​网络丢包是指部分包正常,部分包被丢弃。从现象上看就不是网络一直不通,而是:偶尔不通。速度慢(丢包导致重传)。排查思路​TODO可能原因​高并发NAT导致conntrack插入冲突​如果高并发并且做了NAT,比如使用了ip-masq-agent,对集群外的网段或公......
  • Linux 网络编程从入门到进阶 学习指南
    前言大家好,我是小康。在上一篇文章中,我们探讨了Linux系统编程的诸多基础构件,包括文件操作、进程管理和线程同步等,接下来,我们将视野扩展到网络世界。在这个新篇章里,我们要让应用跳出单机限制,学会在网络上跨机器交流信息。接下来,我们要深入套接字(sockets)和TCP/IP协议,揭示如何......
  • 关于NFS 网络文件共享服务的安装、配置
    NFS中文意思是网络文件系统。它用于类linux系统之间的文件共享、类似windows系统的文件共享、磁盘映射。NFS是C/S架构,在server上设置共享目录、并设置哪些共享网段、文件查看方式等。在client上挂载server共享目录到本地就可以查看共享内容。cilent和server之间通过tcp协议进......
  • 神经网络基础
    (个人学习所用,内容来源于网络,侵权删)1.感知机感知机由Rosenblatt在1957年提出,是神经网络的基础,该思想受生物学启发(参照下图),在其看来,人的大脑可以看作一个生物的神经网络,其最小的单元是神经元。人的神经网络由这样的一些神经元组成,它接受一些信号,这些信号可能是眼睛看到的光学......
  • 神经网络优化篇:详解深度学习框架(Deep Learning frameworks)
    深度学习框架一小点作者内心os:24年春节已过完,从熟悉的地方又回到陌生的地方谋生,愿新的一年都得偿所愿,心想事成。学到这会儿会发现,除非应用更复杂的模型,例如卷积神经网络,或者循环神经网络,或者当开始应用很大的模型,否则它就越来越不实用了,至少对大多数人而言,从零开始全部靠自己......
  • CentOS在无网络环境下,用离线源yum安装软件
    先说大致步骤:1、前提假设:当前无网络的目标服务器是A,我们需要先准备一台服务器B;2、在B上面用yum先把软件安装完成。3、然后用createrepo将B中的包拷贝出来,并传到A上(用U盘或者内网SSH等方法都行);4、修改A上的yum源为刚刚拷过来的本地文件;5、在A上就可以安装了。 以安装nginx......
  • 深度学习-卷积神经网络基础2-43
    目录1.池化层2.CNN的一般架构3.经典的LeNet4代码5代码21.池化层为什么要有池化层?目标就是降采样subsample,shrink,减少计算负荷,内存使用,参数数量(也可防止过拟合)正如卷积神经网络一样,在池化层中的每个神经元被连接到上面一层输出的神经元,只对应一小块感受野的区域。我们必......
  • 基于yolov2深度学习网络的血细胞检测算法matlab仿真
    1.算法运行效果图预览 2.算法运行软件版本MATLAB2022a 3.算法理论概述         血细胞检测是医学图像处理领域的重要任务之一,对于疾病的诊断和治疗具有重要意义。近年来,深度学习在医学图像处理领域取得了显著成果,尤其是目标检测算法在血细胞检测方面表现出......
  • input,type为number时隐藏点击按钮和限制输入最大最小值
    //隐藏点击按钮input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{-webkit-appearance:none;}input[type='number']{-moz-appearance:textfield;}//解决输入中文后光标上移的问题.el-input__inner{line-height:1px!important;}//......