Cod sursa(job #3147282)

Utilizator mircea_007Mircea Rebengiuc mircea_007 Data 25 august 2023 13:16:20
Problema Flux maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.11 kb
#include <stdio.h>
#include <vector>

// .... :( ma pis pe stl
#include <queue>

const int MAXN = 350;
const int MAXM = 12500;
const int INF = 1e9;
const int NIL = -1;

int cap[MAXN][MAXN];
int cost[MAXN][MAXN];
std::vector<int> adj[MAXN];

int prev_dist[MAXN]; // distanta de la iteratia precedenta
int real_dist[MAXN]; // distanta pe costuri adevarate (scadem potentialele (prev_dist))
int dist[MAXN]; // distanta pe costuri reduse
int par[MAXN]; // parintele in arborele parcurgerii djikstra

// bellman-ford
void init_potentials( int n, int src ){
  int u;
  
  std::queue<int> q( { src } );

  for( u = 0 ; u < n ; u++ )
    dist[u] = +INF;
  dist[src] = 0;

  while( !q.empty() ){
    u = q.front();
    q.pop();

    for( int v : adj[u] )
      if( cap[u][v] && dist[u] + cost[u][v] < dist[v] ){
        dist[v] = dist[u] + cost[u][v];
        q.push( v );
      }
  }

  for( u = 0 ; u < n ; u++ )
    prev_dist[u] = dist[u];
}

// djikstra
bool find_path( int n, int src, int dest ){
  // nu facem cu set, pentru ca chiar daca nu trebuie sa iteram
  // peste elementele gresite set are constanta mai mare (heap vs RB tree)
  int u, aux;
  std::pair<int, int> top;

  std::priority_queue<std::pair<int, int>> pq;

  for( u = 0 ; u < n ; u++ )
    dist[u] = +INF;
  dist[src] = 0;
  par[src] = NIL;

  pq.push( std::make_pair( 0, src ) );

  while( !pq.empty() ){
    top = pq.top();
    pq.pop();

    if( dist[top.second] == -top.first ){
      u = top.second;

      for( int v : adj[u] )
        if( cap[u][v] ){
          aux = cost[u][v] + prev_dist[u] - prev_dist[v]; // folosim prev_dist[] ca potentiale

          if( dist[u] + aux < dist[v] ){
            par[v] = u;
            dist[v] = dist[u] + aux;
            pq.push( std::make_pair( -dist[v], v ) );
          }
        }
    }
  }

  // get real_dist[] as to not mess up prev_dist[]
  for( u = 0 ; u < n ; u++ )
    real_dist[u] = dist[u] + prev_dist[u] - prev_dist[src];

  // now we can safely overwrite
  for( u = 0 ; u < n ; u++ )
    prev_dist[u] = real_dist[u];

  return dist[dest] < +INF;
}

int main(){
  FILE *fin  = fopen( "fmcm.in", "r" );
  FILE *fout = fopen( "fmcm.out", "w" );

  int n, m, src, dest, i, a, b, flow, flow_cost, augment_flow, augment_cost;

  fscanf( fin, "%d%d%d%d", &n, &m, &src, &dest );
  src--;
  dest--;

  for( i = 0 ; i < m ; i++ ){
    fscanf( fin, "%d%d", &a, &b );
    a--;
    b--;

    adj[a].push_back( b );
    adj[b].push_back( a );

    fscanf( fin, "%d%d", &cap[a][b], &cost[a][b] );
    cost[b][a] = -cost[a][b];
  }

  flow = flow_cost = 0;
  init_potentials( n, src );
  while( find_path( n, src, dest ) ){
    // now we augment
    augment_flow = +INF;
    augment_cost = 0;
    for( a = dest ; par[a] != NIL ; a = par[a] ){
      augment_flow = cap[par[a]][a] < augment_flow ? cap[par[a]][a] : augment_flow;
      augment_cost += cost[par[a]][a];
    }

    flow += augment_flow;
    flow_cost += augment_flow * augment_cost;
    for( a = dest ; par[a] != NIL ; a = par[a] ){
      cap[par[a]][a] -= augment_flow;
      cap[a][par[a]] += augment_flow;
    }
  }

  fprintf( fout, "%d\n", flow_cost );

  fclose( fin );
  fclose( fout );
  return 0;
}