Cod sursa(job #2010542)

Utilizator GoogalAbabei Daniel Googal Data 13 august 2017 15:31:16
Problema Cc Scor 50
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.5 kb
#include <algorithm>
#include <iostream>
#include <fstream>
#include <climits>
#include <cassert>
#include <bitset>
#include <vector>
#include <queue>

using namespace std;

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

const int NMAX = 2 * (100 + 1);

struct Edge{
  int to;
  int rev;
  int flow;
  int cap;
  int cost;
};

struct Node{
  int node;
  int d;

  bool operator> (Node other) const{
    return d > other.d;
  }
};

int n, src, dest;
int dist[1 + NMAX], distdij[1 + NMAX];
bitset<1 + NMAX> vis;
int prevnode[1 + NMAX], prevedge[1 + NMAX], pushflow[1 + NMAX];

vector < Edge > g[1 + NMAX];

void addedge(int from, int to, int cost){
  Edge direct  = {to, g[to].size(), 0, 1, cost};
  Edge inverse = {from, g[from].size(), 0, 0, -cost};

  g[from].push_back(direct);
  g[to].push_back(inverse);
}

void bellmanford(){
  queue < int > q;
  fill(dist, dist + dest + 1, INT_MAX);
  dist[src] = 0;
  q.push(src);

  while(!q.empty()){
    int from = q.front();
    vis[from] = 0;
    q.pop();

    for(int i = 0; i < g[from].size(); i++){
      Edge &e = g[from][i];
      if(e.flow < e.cap){
        int to = e.to;
        int newdist = dist[from] + e.cost;
        if(newdist < dist[to]){
          dist[to] = newdist;
          if(vis[to] == 0){
            q.push(to);
            vis[to] = 1;
          }
        }
      }
    }
  }
}

void dijkstra(){
  vis = 0;
  distdij[src] = 0;
  pushflow[src] = INT_MAX;

  priority_queue<Node, vector <Node>, greater<Node> > pq;
  pq.push({src, distdij[src]});

  while(!pq.empty()){
    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(vis[e.to] == 0){
          int to = e.to;
          if(e.flow < e.cap){
            int newdistdij = distdij[from] + e.cost + dist[from] - dist[to];
            if(newdistdij < distdij[to]){
              distdij[to] = newdistdij;
              prevnode[to] = from;
              prevedge[to] = i;
              pushflow[to] = min(pushflow[from], e.cap - e.flow);
              pq.push({to, distdij[to]});
            }
          }
        }
      }
    }
  }
}

void mincostflow(int &flow, int &flowcost) {
  bellmanford();
  //cout << "BF\n";

  flow = flowcost = 0;
  while(distdij[dest] < INT_MAX) {
    fill(distdij + 1, distdij + dest + 1, INT_MAX);
    dijkstra();
    //cout << "DJ\n";
    if(distdij[dest] < INT_MAX) {

      //new level graph
      for(int i = 1; i <= n; i++){
        dist[i] += distdij[i];
      }

      //blocking flow
      int deltaflow = pushflow[dest];
      flow += deltaflow;
      for(int to = dest; to != src; to = prevnode[to]) {
        Edge &e = g[prevnode[to]][prevedge[to]];
        e.flow += deltaflow;
        g[to][e.rev].flow -= deltaflow;
        flowcost += deltaflow * e.cost;
        //cout << deltaflow << ' ' << e.cost << ' ' << flowcost << '\n';
      }
    }
  }
}

int main()
{
  in >> n;
  src = 0;
  dest = 2 * n + 1;
  for(int i = 1; i <= n; i++){
    for(int j = 1; j <= n; j++){
      int x;
      in >> x;
      addedge(i, j + n, x);
    }
  }

  for(int i = 1; i <= n; i++)
    addedge(src, i, 0);
  for(int i = n + 1; i <= 2 * n; i++)
    addedge(i, dest, 0);

  int flow, flowcost;
  mincostflow(flow, flowcost);
  assert(0 < flowcost);
  assert(flow == n);
  out << flowcost << '\n';

  in.close();
  out.close();
  return 0;
}