Реализация поиска максимального потока методом проталкивания предпотока

Сайт: Информатикс
Курс: Алгоритмы на графах
Книга: Реализация поиска максимального потока методом проталкивания предпотока
Напечатано:: Гость
Дата: Пятница, 18 Июль 2025, 15:28

Оглавление

//(C) Igor Kvasov
{поиск максимального потока методом проталкивания предпотока
в его реализации "поднять-и-в начало"}
var
  n,m,i,u,v,w,nL,head,vin,vout,oldh,ans:longint;
  f,c,e:array[1..100,1..100]of longint;
  ne,cur,next,prev,L,s,h:array[1..100]of longint;

procedure Push(u,v:longint);
var
  d:longint;

begin
  d:=c[u,v]-f[u,v];
  if d>s[u] then d:=s[u];
  s[u]:=s[u]-d; s[v]:=s[v]+d;
  f[u,v]:=f[u,v]+d;
  f[v,u]:=-f[u,v];
end;

procedure Lift(u:longint);
var
  v:longint;

begin
  h[u]:=2*n;
  for v:=1 to n do if (c[u,v]-f[u,v]>0)and(h[v]<h[u]) then h[u]:=h[v];
  inc(h[u]);
end;

procedure Discharge(u:longint);
begin
  while s[u]>0 do begin
    v:=e[u,cur[u]];
    if v=0 then begin
      Lift(u); cur[u]:=1;
    end else if (c[u,v]-f[u,v]>0)and(h[u]=h[v]+1) then Push(u,v)
             else inc(cur[u]);
  end;
end;

begin
  read(n,m,vin,vout);
  for i:=1 to m do begin
    read(u,v,w);
    if c[v,u]=0 then begin
      inc(ne[u]); e[u,ne[u]]:=v;
      inc(ne[v]); e[v,ne[v]]:=u;
    end;
    c[u,v]:=w;
  end;
  close(input);
  h[vin]:=n;
  for v:=1 to n do begin
    if c[vin,v]>0 then begin
      f[vin,v]:=c[vin,v]; f[v,vin]:=-c[vin,v];
      s[v]:=s[v]+c[vin,v];
    end;
    if (v<>vin)and(v<>vout) then begin
      cur[v]:=1;
      inc(nL); L[nL]:=v;
    end;
  end;
  for i:=1 to nL do begin
    prev[i]:=i-1; next[i]:=i+1;
  end;
  if nL<>0 then begin
    next[nL]:=0;
    head:=1; i:=head;
  end else i:=0;
  while i>0 do begin
    u:=L[i];
    oldh:=h[u];
    Discharge(u);
    if (h[u]<>oldh)and(i<>head) then begin
      if next[i]<>0 then prev[next[i]]:=prev[i];
      next[prev[i]]:=next[i];
      next[i]:=head;
      prev[i]:=0; prev[head]:=i;
      head:=i;
    end;
    i:=next[i];
  end;
  ans:=0;
  for u:=1 to n do ans:=ans+f[vin,u];
  write(ans);
end.

/*********************************************************
   Simple implementation of the push-relabel algorithm
   for the maximal network flow.
   Input format:
   n s t - number of nodes, source and sink
   then follow c[i][j], if i == j then number is ommited.
   See read() function.
*********************************************************/

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <algorithm>
#include <list>

using namespace std;
const int N = 2000;

int e[N],c[N][N],h[N];
int n,s,t;


void push(int u,int v)
{
  int f = min(e[u],c[u][v]);
  e[u] -= f; e[v] += f;
  c[u][v] -= f; c[v][u] += f;
}

void lift(int u)
{
  int min = 3 * n + 1;
  
  for (int i = 0;i < n;i++)
    if (c[u][i] && (h[i] < min))
      min = h[i];
  h[u] = min + 1;
}

void discharge(int u)
{
  int v = 0;
  while (e[u] > 0)
  {
    if (c[u][v] && h[u] == h[v] + 1)
    {
      push(u,v); v = 0; continue;
    }
    v++;
    if (v == n)
    {
      lift(u); v = 0;
    }
  }
}

void read()
{
  cin >> n >> s >> t;
  
  for (int i = 0;i < n;i++)
    for (int j = 0;j < n;j++)
    {
      if (i == j)
        continue;
      cin >> c[i][j];
    }
}

void init()
{
  read();
  for (int i = 0;i < n;i++)
  {
    if (i == s)
      continue;
    e[i] = c[s][i]; c[i][s] += c[s][i];
  }
  h[s] = n;
}


int main(int argc, char *argv[])
{
  list<int> l;
  list<int>::iterator cur;
  int old;
  
  init();
  
  for (int i = 0;i < n;i++)
    if (i != s && i != t)
      l.push_front(i);
  cur = l.begin();
  
  while (cur != l.end())
  {
    old = h[*cur];
    discharge(*cur);
    if (h[*cur] != old)
    {
      l.push_front(*cur);l.erase(cur);cur = l.begin();
    }
    cur++;
  }
  cout << e[t];
  return 0;
}