Cod sursa(job #2085519)

Utilizator AlexandruLuchianov1Alex Luchianov AlexandruLuchianov1 Data 10 decembrie 2017 12:19:02
Problema Flux maxim de cost minim Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 4.11 kb
#include <queue>
#include <vector>
#include <climits>
#include <iostream>
#include <fstream>
#include <bitset>

using namespace std;

ifstream in("fmcm.in");
ofstream out("fmcm.out");

int const nmax = 350;

struct Edge{
  int to;
  int rev;
  int cost;
  int cap;
  int flow;
};
vector<Edge> g[1 + nmax];

int n, m, src, dest;
int dist[1 + nmax], dist2[1 + nmax];

void addedge(int a, int b, int cap, int cost) {
  g[a].push_back({b, g[b].size(),      cost, cap, 0});
  g[b].push_back({a, g[a].size() - 1, -cost,   0, 0});
}

void bellmanford(){ //pentru O(m*n) trebuie sa faci optimizare cu vector de vizitat
  for(int i = 1 ; i <= n ;i++){
    dist[i] = INT_MAX;
  }
  dist[src] = 0;
  queue<int> q;
  q.push(src);
  while(0 < q.size()) {
    int from = q.front();
    q.pop();
    for(int i = 0; i < g[from].size(); i++) {
      Edge e = g[from][i];
      if(e.flow < e.cap) {  //mare, mare atentie
        if(dist[from] + e.cost < dist[e.to]) {
          dist[e.to] = dist[from] + e.cost;
          q.push(e.to);
        }
      }
    }
  }
}

//Ca sa updatezi toate muchiile, ai nevoie de O(m) pasi
//dar, costul nou al muchiei depinde de costul vechi plus o expresie care depinde de starile nodurilor cost_nou - cost_vechi + dist[nod1] - dist[nod2]
//Deci daca suntem destepti si mutam update-ul de la muchii la starile modurilor, atunci update-ul se face in O(n) pasi
//Adica nu mai updatez explicit costurile muchiilor, le updatez implicit!!
//am nevoie de costurile muchiilor in Dijkstra, deci doar in Dijkstra trebuie sa-mi aduc aminte sa updatezu cu dist[nod1] - dist[nod2]
//facem acum implementarea implicita si-ti ramane tie ca tema sa faci implementarea explicita.

struct Node {
  int node;
  int cost;

  bool operator > (Node a) const {
    return (cost > a.cost);
  }
};

//primeste dist si returneaza dist2
//detaliu de implementare: dupa dijkstra trebuie sa augmentam
//daca presaram niste sare in timpul lui dijkstra, nu trebuie sa mai facem DFS
//De ce aici putem presara niste sare si la Dinic nu?
//La Dinic avem blocking flow (ami multe drumuri de augmentare)
//pe cand aici dupa fiecare drum de augmentare, trebuie recalculat dist-ul
//si atunci daca tot gasim decat un singur drum cu dijkstra, dar hai punem sa punem sare

int prevnode[1 + nmax], prevedge[1 + nmax], augment[1 + nmax];
bitset<1 + nmax> vis;  //vis = 0, se initializeaza usor

void dijkstra() {
  vis = 0;
  for(int i = 1; i <= n ;i++){
    dist2[i] = INT_MAX;
  }
  priority_queue<Node, vector<Node> , greater<Node> > pq;
  dist2[src] = 0;
  augment[src] = INT_MAX;
  pq.push({src , dist2[src]});
  while(0 < pq.size()){
    int from = pq.top().node;
    pq.pop();
    if(vis[from] == 0) {
      vis[from] = 1;
      for(int i = 0; i < g[from].size(); i++) {
        Edge e = g[from][i];
        if(e.flow < e.cap) {  //daca muchia e saturata, nici nu discuti
          int newdist = dist2[from] + (e.cost + dist[from] - dist[e.to]); //cost modif.
          if(newdist < dist2[e.to]){
            dist2[e.to] = newdist;
            pq.push({e.to, newdist});
            prevnode[e.to] = from;
            prevedge[e.to] = i;
            augment[e.to] = min(augment[from], e.cap - e.flow);
          }
        }
      }
    }
  }
}

//tot  algoritmul de fmcm

void fmcm(int &flow, int &flowcost) {
  bellmanford();
  flow = flowcost = 0;
  int t = 0;
  while(dist[dest] < INT_MAX && dist2[dest] < INT_MAX) {
    dijkstra();
    if(dist2[dest] < INT_MAX) {
      flow += augment[dest];
      int x = dest;
      while(x != src){
        Edge &e = g[prevnode[x]][prevedge[x]];
        e.flow += augment[dest];
        g[prevnode[x]][e.rev].flow -= augment[dest];
        flowcost += e.cost * augment[dest];
        x = prevnode[x];
      }
      for(int i = 1 ; i <= n ;i++){
        dist[i] += dist2[i];
      }
    }

  }
}

int main() {
  in >> n >> m >> src >> dest;
  for(int i = 1 ; i <= m ;i++) {
    int x, y, cap, c;
    in >> x >> y >> cap >> c;
    addedge(x, y, cap, c);
  }
  int flow, flowcost;
  fmcm(flow , flowcost);
  out << flowcost;
  return 0;
}