Cod sursa(job #961036)

Utilizator primulDarie Sergiu primul Data 11 iunie 2013 16:27:21
Problema Cc Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 6.95 kb
/*
 Catalin-Stefan Tiseanu
  
 Pre-written code is assembled from various sources found online.
 Big thanks to the community !
 */
 
// Pre-written code below
 
using namespace std;
 
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
 
//#define DEBUG
 
#ifdef DEBUG
#define debug(args...)            {dbg,args; cerr<<endl;}
#else
#define debug(args...)              // Just strip off all debug tokens
#endif
 
struct debugger
{
  template<typename T> debugger& operator , (const T& v)
  {
  cerr<<v<<" ";
  return *this;
  }
} dbg;
 
// templates
template<typename T> int size(const T& c) { return int(c.size()); }
template<typename T> T abs(T x) { return x < 0 ? -x : x; }
template<typename T> T sqr(T x) { return x*x; }
template<typename T> bool remin(T& x, T y) { if (x <= y) return false; x = y; return true; }
template<typename T> bool remax(T& x, T y) { if (x >= y) return false; x = y; return true; }
 
// misc
#define EPSILON              1e-7
 
// types
typedef long long            int64;
typedef unsigned long long   uint64;
 
// shortcuts
#define all(_xx)             _xx.begin(), _xx.end()
 
#define pb                   push_back
#define vi                   vector<int>
#define vpii                 vector<pair<int,int> >
 
#define pii pair<int,int>
#define mp(XX, YY)           make_pair(XX, YY)
#define fi                   first
#define se                   second
 
#define SS                   stringstream
 
// for loops
#define re(II, NN)           for (int II(0), _NN(NN); (II) < (NN); ++(II))
#define fod(II, XX, YY)      for (int II(XX), _YY(YY); (II) >= (_YY); --(II))
#define fo(II, XX, YY)       for (int II(XX), _YY(YY); (II) <= (_YY); ++(II))
 
// Useful hardware instructions
#define bitcount             __builtin_popcount
#define gcd                  __gcd
 
// Useful all around
#define checkbit(n,b)        ( (n >> b) & 1)
#define DREP(a)              sort(all(a));a.erase(unique(all(a)),a.end())
#define INDEX(arr,ind)       (lower_bound(all(arr),ind)-arr.begin())
 
// Note: Thanks to Misof for the Mincost-Maxflow code below
template<class T, class U>
class MincostMaxflow {
public:
  class edge {
  public:
    int source, destination;
    T capacity, residue;
    U cost;
    edge(int s, int d, T cap, T res, U cost)
    : source(s), destination(d), capacity(cap), residue(res), cost(cost) { }
  };
   
  vector< vector<int> > V;
  vector<edge> E;
  void clear();
  void addArc(int source, int destination, T capacity, U cost);
  pair<T,U> getFlow(int source, int sink);
};
 
template<class T, class U> void MincostMaxflow<T,U>::clear() { V.clear(); E.clear(); }
 
template<class T, class U>
void MincostMaxflow<T,U>::addArc(int source, int destination, T capacity, U cost) {
  // cout << "addArc " << source << " " << destination << " " << capacity << " " << cost << endl;
  int e = E.size();
  if (source >= int(V.size())) V.resize(source+1);
  if (destination >= int(V.size())) V.resize(destination+1);
  V[source].push_back( e );
  V[destination].push_back( e+1 );
  E.push_back(edge(source,destination,capacity,capacity,cost));
  E.push_back(edge(destination,source,capacity,0,-cost));
}
 
template<class T, class U>
pair<T,U> MincostMaxflow<T,U>::getFlow(int source, int sink) {
  if (source >= int(V.size())) V.resize(source+1);
  if (sink >= int(V.size())) V.resize(sink+1);
   
  int N = V.size(), M = E.size();
  T flowSize = 0;
  U flowCost = 0;
  T Tinfinity = 1; while (2*Tinfinity > Tinfinity) Tinfinity *= 2;
  U Uinfinity = 1; while (2*Uinfinity > Uinfinity) Uinfinity *= 2;
  U Uepsilon = 1; for (int i=0; i<30; i++) Uepsilon /= 2;
  vector<T> flow(M,0);
  vector<U> potential(N,0);
  while (1) {
    // use dijkstra to find an augmenting path
    vector<int> from(N,-1);
    vector<U> dist(N,Uinfinity);
     
    priority_queue< pair<U,int>, vector<pair<U,int> >, greater<pair<U,int> > > Q;
    Q.push(make_pair(0,source));
    from[source]=-2;
    dist[source] = 0;
     
    while (!Q.empty()) {
      U howFar = Q.top().first;
      int where = Q.top().second;
      Q.pop();
      if (dist[where] < howFar) continue;
       
      for (int i=0; i<int(V[where].size()); i++) {
        if (E[ V[where][i] ].residue == 0) continue;
        int dest = E[ V[where][i] ].destination;
        U cost = E[ V[where][i] ].cost;
        if (dist[dest] > dist[where] + potential[where] - potential[dest] + cost + Uepsilon) {
          dist[dest] = dist[where] + potential[where] - potential[dest] + cost;
          from[dest] = V[where][i];
          Q.push( make_pair( dist[dest],dest ));
        }
      }
    }
     
    // update vertex potentials
    for (int i=0; i<N; i++) {
      if (dist[i]==Uinfinity) potential[i] = Uinfinity;
      else if (potential[i]<Uinfinity) potential[i] += dist[i];
    }
     
    // if there is no path, we are done
    if (from[sink] == -1) return make_pair(flowSize,flowCost);
     
    // construct an augmenting path
    T canPush = Tinfinity;
    int where = sink;
     
    while (1) {
      if (from[where]==-2) break;
      canPush = min(canPush, E[ from[where] ].residue );
      where = E[ from[where] ].source;
    }
     
    // update along the path
    where = sink;
    while (1) {
      if (from[where]==-2) break;
      E[ from[where] ].residue -= canPush;
      E[ from[where]^1 ].residue += canPush;
      flowCost += canPush * E[ from[where] ].cost;
      where = E[ from[where] ].source;
    }
    flowSize += canPush;
  }
  return make_pair(-1,47);
}
 
 
// Code written during the competition below
 
int N, A[1111][1111];
 
void my_test() {
  N = 100;
  fo (i, 1, N)
    fo (j, 1, N)
      A[i][j] = rand() % 10001 + 1;
}
 
 
int main() {
  freopen("cc.in", "r", stdin);
  freopen("cc.out", "w", stdout);
   
  MincostMaxflow <int, int> MF;
   
  scanf("%d", &N);
   
  fo(i, 1, N)
    fo (j, 1, N)
      scanf("%d", &A[i][j]);
   
  //my_test();
   
  fo (i, 1, N)
    fo (j, 1, N)
      MF.addArc(i, j + N, 1, A[i][j]);
   
  fo (i, 1, N) MF.addArc(0, i, 1, 0);
  fo (i, 1, N) MF.addArc(i + N, 2 * N + 1, 1, 0);
   
  pii result = MF.getFlow(0, 2 * N + 1);
  printf("%d\n", result.se);
   
  re(i, size(MF.E)) {
    if (!MF.E[i].residue && MF.E[i].cost >= 0 &&
        MF.E[i].source > 0 &&
        MF.E[i].source < 2 * N + 1 &&
        MF.E[i].destination > 0 &&
        MF.E[i].destination < 2 * N + 1) {
      debug(MF.E[i].source, " ", MF.E[i].destination, " ", MF.E[i].cost);
    }
  }
   
  return 0;
}