Cod sursa(job #2949529)

Utilizator FunnyStockyMihnea Andreescu FunnyStocky Data 30 noiembrie 2022 21:48:54
Problema Flux maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.61 kb
#include <bits/stdc++.h>

using namespace std;

struct Edge
{
  int to;
  int cap;
  int cost;
  int inv;
};

const int FN = 350 + 7;
const int FMAXDEG = FN;
const int INF = (int) 1e9 + 7;
int fln;
int fls;
int fld;
Edge fladj[FN][FMAXDEG];
int fltop[FN];
int fldist[FN];
bool flvis[FN];
int flparid[FN];
int ini[FN];
int flflow;
long long flflowcost;
queue<int> flq;
priority_queue<pair<int, int>> flqq;

void flinit(int n, int s, int d)
{
  fln = n;
  fls = s;
  fld = d;
  flflow = 0;
  flflowcost = 0;
  assert(1 <= fls && fls <= fln);
  assert(1 <= fld && fld <= fln);
  for (int i = 1; i <= fln; i++)
  {
    fltop[i] = 0;
  }
}

void fladdedge(int a, int b, int cap, int cost)
{
  assert(1 <= a && a <= fln);
  assert(1 <= b && b <= fln);
  /// be careful here if you make fltop[a]++ inside :)) like this "fladj[a][++fltop[a]]"
  fltop[a]++;
  fltop[b]++;
  fladj[a][fltop[a]] = {b, cap, cost, fltop[b]};
  fladj[b][fltop[b]] = {a, 0, -cost, fltop[a]};
}

bool flbellman()
{
  for (int i = 1; i <= fln; i++)
  {
    fldist[i] = INF;
    flvis[i] = 0;
  }
  flq.push(fls);
  flvis[fls] = 1;
  fldist[fls] = 0;
  while (!flq.empty())
  {
    int a = flq.front();
    assert(flvis[a] == 1);
    flvis[a] = 0;
    flq.pop();
    for (int j = 1; j <= fltop[a]; j++)
    {
      if (fladj[a][j].cap > 0 && fldist[a] + fladj[a][j].cost < fldist[fladj[a][j].to])
      {
        fldist[fladj[a][j].to] = fldist[a] + fladj[a][j].cost;
        flparid[fladj[a][j].to] = fladj[a][j].inv;
        assert(fladj[fladj[a][j].to][fladj[a][j].inv].to == a);
        if (!flvis[fladj[a][j].to])
        {
          flvis[fladj[a][j].to] = 1;
          flq.push(fladj[a][j].to);
        }
      }
    }
  }
  if (fldist[fld] == INF)
  {
    return 0;
  }
  int mn = INF, v = fld, s = 0;
  while (v != fls)
  {
    int cur = flparid[v];
  ///  cout << "v = " << v << "\n";
    assert(fladj[fladj[v][cur].to][fladj[v][cur].inv].to == v);
    mn = min(mn, fladj[fladj[v][cur].to][fladj[v][cur].inv].cap);
    v = fladj[v][cur].to;
  }
  assert(mn > 0);
  v = fld;
  while (v != fls)
  {
    int cur = flparid[v];
    assert(fladj[fladj[v][cur].to][fladj[v][cur].inv].to == v);
    fladj[fladj[v][cur].to][fladj[v][cur].inv].cap -= mn;
    fladj[v][cur].cap += mn;
    s += fladj[fladj[v][cur].to][fladj[v][cur].inv].cost;
    v = fladj[v][cur].to;
  }
#ifdef ONPC
 /* cout << s << " vs " << fldist[fld] << "\n";
  cout << "fls = " << fls << "\n";
  cout << "fld = " << fld << "\n";
  for (int i = 1; i <= fln; i++)
  {
    cout << "fldist[" << i << "] = " << fldist[i] << "\n";
  }*/
#endif // ONPC
  assert(s == fldist[fld]);
  flflow += mn;
  flflowcost += 1LL * mn * fldist[fld];
  return 1;
}

bool flbellman2()
{
  for (int i = 1; i <= fln; i++)
  {
    ini[i] = fldist[i];
    fldist[i] = INF;
  }
  flqq.push({0, fls});
  fldist[fls] = 0;
  bool tg = 0;
  while (!flqq.empty())
  {
    pair<int, int> pr = flqq.top();
    flqq.pop();
    pr.first *= -1;
    int a = pr.second;
    if (fldist[a] != pr.first)
    {
      continue;
    }

    if (a == fld)
    {
      tg = 1;
    }
    for (int j = 1; j <= fltop[a]; j++)
    {
     // cout << a << " " << fladj[a][j].to;
     // cout << " : " << ini[fladj[a][j].to] << " | " << fladj[a][j].cost + ini[fladj[a][j].to] << " " << ini[a] << "\n";
      if (fladj[a][j].cap == 0)
      {
        continue;
      }
      assert(fladj[a][j].cost + ini[a] >= ini[fladj[a][j].to]);
      if (fladj[a][j].cap > 0 && fldist[a] + fladj[a][j].cost + ini[a] - ini[fladj[a][j].to] < fldist[fladj[a][j].to])
      {
        fldist[fladj[a][j].to] = fldist[a] + fladj[a][j].cost + ini[a] - ini[fladj[a][j].to];
        flparid[fladj[a][j].to] = fladj[a][j].inv;
        flqq.push({-fldist[fladj[a][j].to], fladj[a][j].to});
        assert(fladj[fladj[a][j].to][fladj[a][j].inv].to == a);
      }
    }
  }
  for (int i = 1; i <= fln; i++)
  {
    fldist[i] += ini[i];
    fldist[i] = min(fldist[i], INF);
  }
  if (tg == 0)
  {
    return 0;
  }
  int mn = INF, v = fld, s = 0;
  while (v != fls)
  {
    int cur = flparid[v];
  ///  cout << "v = " << v << "\n";
    assert(fladj[fladj[v][cur].to][fladj[v][cur].inv].to == v);
    mn = min(mn, fladj[fladj[v][cur].to][fladj[v][cur].inv].cap);
    v = fladj[v][cur].to;
  }
  assert(mn > 0);
  v = fld;
  while (v != fls)
  {
    int cur = flparid[v];
    assert(fladj[fladj[v][cur].to][fladj[v][cur].inv].to == v);
    fladj[fladj[v][cur].to][fladj[v][cur].inv].cap -= mn;
    fladj[v][cur].cap += mn;
    s += fladj[fladj[v][cur].to][fladj[v][cur].inv].cost;
    v = fladj[v][cur].to;
  }
#ifdef ONPC
 /* cout << s << " vs " << fldist[fld] << "\n";
  cout << "fls = " << fls << "\n";
  cout << "fld = " << fld << "\n";
  for (int i = 1; i <= fln; i++)
  {
    cout << "fldist[" << i << "] = " << fldist[i] << "\n";
  }*/
#endif // ONPC
  assert(s == fldist[fld]);
  flflow += mn;
  flflowcost += 1LL * mn * fldist[fld];
  return 1;
}

void flpumpflow()
{
  if (!flbellman())
  {
    return;
  }
  while (flbellman2())
  {

  }
}

signed main()
{
#ifdef ONPC
  freopen ("input.txt", "r", stdin);
#endif // ONPC
#ifndef ONPC
  ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  freopen ("fmcm.in", "r", stdin);
  freopen ("fmcm.out", "w", stdout);
#endif // ONPC

  int n, m, s, d;
  cin >> n >> m >> s >> d;
  flinit(n, s, d);
  for (int i = 1; i <= m; i++)
  {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    fladdedge(a, b, c, d);
  }
  flpumpflow();
  cout << flflowcost << "\n";

  return 0;
}
/**

**/