Cod sursa(job #610391)

Utilizator mgntMarius B mgnt Data 26 august 2011 22:36:51
Problema Algola Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 7.25 kb
//  Solutie:
//    
//    b - numarul membrilor organizatiei; b<=50.
//    m - numarul drumurilor intre orase (muchiilor); m<=300
//    n - numarul oraselor (arcelor); n<=50.
//    
//    T unitati de timp sunt suficiente, daca fluxul maxim in reteaua de transport
//       ((v,t),(w,t+1)) pentru 0<=t<T unde {v,w} este muchie in graful oraselor,
//       ((v,t),(v,t+1)) pentru 0<=t<T unde v este oras,
//       ((0,0), (v,0))  unde v este un oras
//       ((v,T), (0,T)) unde v este un oras
//       s = (0,0), t = (0,T+1)
//    este egal cu numarul membrilor organizatiei.
//    
//    Fluxul maxim este cel mult egal cu b.
//    m' - numarul de arce ale retelei reziduale.
//    Cu BFS, un drum de la s la t se gaseste in cel mult m' operatii.
//    Fluxul maxim se poate calcula cu ford-fulkerson, in cel mult b*m' operatii.
//    
//    Topt <= Tmax=((n-1)+(b-1)) :
//       {1,2},{2,3},...,{n-1,n}, pe fiecare din aceste muchii trece maxim 1 om, b oameni in n.

#include <fstream>
#include <algorithm>
#include <vector>
#include <queue>

int const maxn = 50;
int const maxm = 300;
int const maxb = 50;
int const minc = 1;
int const maxc = 10;

struct endp2
{ int y, c; 
  endp2() throw ( ) : y(-1), c(-1) { }
  endp2(int y1, int c1) throw ( ) : y(y1), c(c1) { } 
};

struct endp3
{ int y, c, f, i;
  endp3() throw ( ) : y(-1), c(-1), f(-1), i(-1) { }
  endp3(int y1, int c1, int f1, int i1) throw ( )
  : y(y1), c(c1), f(f1), i(i1) { }
};

class algola
{ // input
  int a_n;
  std::vector<int> a_b;
  std::vector<std::vector<endp2> > a_adj;
  int a_b_sum;
  // flow
  int a_n3;
  int a_source; int a_sink;
  std::vector<std::vector<endp3> > a_adj3;
  int a_flow_value;
  // max flow storage
  std::vector<int> a_fxy;
  std::vector<int> a_bfs_queue;
  // answer, status
  int a_ans;
  bool a_ok;
  // helper (2) methods
  void max_flow() throw ( );
  void update_flow_network(int t);
  void construct_flow_network();
  // helper methods
  bool write();
  void solve();
  bool read();
  bool process();
  public:
  algola();
  bool get_ok() const throw();
};

bool
algola::get_ok() const throw()
{ return a_ok; }

algola::algola()
: a_ok(process())
{ }

bool
algola::process()
{ bool ok; ok = read();  if(!ok) { return ok; }
  solve(); ok = write(); return ok;
}

bool
algola::read()
{ // read input
  bool ok;
  std::ifstream is("algola.in");
  ok = is.good(); if(!ok) { return ok; }
  int n; int m; is >> n >> m;
  ok = ((0<n)&&(maxn>=n)); if(!ok) { return ok; }
  ok = ((0<m)&&(maxm>=m)); if(!ok) { return ok; }
  std::vector<int> b(1+n);
  int x; for(x=1; n>=x; ++x)
  { is >> b[x];
    ok = (0<=b[x]); if(!ok) { return ok; }
  }
  int b_sum; b_sum = 0; for(x=1; n>=x; ++x) { b_sum += b[x]; }
  ok = (b_sum<=maxb); if(!ok) { return ok; }
  std::vector<std::vector<endp2> > adj(1+n);
  int i; int y; int c;
  for(i=0; m>i; ++i)
  { is >> x >> y >> c;
    ok = ((1<=x)&&(x<=n)); if(!ok) { return ok; }
    ok = ((1<=y)&&(y<=n)); if(!ok) { return ok; }
    ok = ((minc<=c)&&(c<=maxc)); if(!ok) { return ok; }
    adj[x].push_back(endp2(y, c));
    adj[y].push_back(endp2(x, c));
  }
  ok = is.good(); if(!ok) { return ok; }
  // no-throw
  a_n = n;
  a_b.swap(b);
  a_adj.swap(adj);
  a_b_sum = b_sum;
  return ok;
}

void
algola::solve()
{ // solve
  if(a_b_sum == a_b[1])
  { a_ans = 0; return; }
  int t; t = 1;
  construct_flow_network();
  bool solved; solved = false;
  do
  { max_flow();
    if(a_flow_value == a_b_sum)
    { solved = true; }
    else
    { update_flow_network(t); ++t; }
  }
  while(!solved);
  a_ans = t;
}

bool
algola::write()
{ // write solution
  std::ofstream os("algola.out");
  os << a_ans << std::endl;
  bool ok = os.good(); if(!ok) { return ok; }
  os.close(); ok = os.good(); if(!ok) { return ok; }
  return ok;
}

void
algola::construct_flow_network()
{ std::vector<int> & b (a_b);
  int n; n = a_n; int b_sum; b_sum = a_b_sum;
  int tmax; tmax = ((n-1)+(b_sum-1));
  int tn; tn = (1+tmax) * (n+1); int x;
  int xt; int yt; int ixt; int iyt;
  std::vector<std::vector<endp3> > adj3(tn);
  for(x=1; n>=x; ++x)
  { if(0<b[x])
    { xt = 0*(n+1)+0; yt = 0*(n+1)+x;
      ixt = static_cast<int>(adj3[xt].size());
      iyt = static_cast<int>(adj3[yt].size());
      adj3[xt].push_back(endp3(yt, b[x], 0, iyt));
      adj3[yt].push_back(endp3(xt, 0, 0, ixt));
    }
  }
  std::vector<int> fxy(tn);
  std::vector<int> bfs_queue(tn);
  // no-throw
  a_source = 0*(n+1) + 0;
  a_adj3.swap(adj3);
  a_flow_value = 0;
  a_fxy.swap(fxy);
  a_bfs_queue.swap(bfs_queue);
  update_flow_network(0);
}

void
algola::update_flow_network(int t)
{ std::vector<std::vector<endp2> > & adj (a_adj); 
  int n; n = a_n; int b_sum; b_sum = a_b_sum;
  std::vector<std::vector<endp3> > & adj3(a_adj3);
  int t1; t1 = t; int t2; t2 = 1 + t1;
  int x; int dx; int i; int y; int c;
  int xt; int yt; int ixt; int iyt;
  for(x=1; n>=x; ++x)
  { xt = t1*(n+1)+x; yt = t2*(n+1)+x;
    ixt = static_cast<int>(adj3[xt].size());
    iyt = static_cast<int>(adj3[yt].size());
    adj3[xt].push_back(endp3(yt, b_sum, 0, iyt));
    adj3[yt].push_back(endp3(xt, 0, 0, ixt));
    dx = static_cast<int> (adj[x].size());
    for(i=0; dx>i; ++i)
    { y = adj[x][i].y; c = adj[x][i].c;
      xt = t1*(n+1)+x; yt = t2*(n+1)+y;
      ixt = static_cast<int>(adj3[xt].size());
      iyt = static_cast<int>(adj3[yt].size());
      adj3[xt].push_back(endp3(yt, c, 0, iyt));
      adj3[yt].push_back(endp3(xt, 0, 0, ixt));
    }
  }
  int oldsink; oldsink = t1*(n+1) + 1; int newsink = t2*(n+1) + 1;
  int flow_value; flow_value = a_flow_value;
  i = 0; while(adj3[oldsink][i].y!=newsink) { ++i; }
  adj3[oldsink][i].f =  flow_value; int j; j = adj3[oldsink][i].i;
  adj3[newsink][j].f = -flow_value;
  a_sink   = newsink;
  a_n3 = (1+t2)*(1+n);
}

void
algola::max_flow() throw ( )
{ std::vector<std::vector<endp3 > > & adj3 (a_adj3);
  int n3; n3 = a_n3;
  int source; source = a_source; int sink; sink = a_sink;
  // Start from an initial flow.
  int & flow_value = a_flow_value;
  // The Edmonds - Karp algorithm is a Ford-Fulkerson algorithm.
  std::vector<int> & bfs_queue  (a_bfs_queue);
  int queue_in; int queue_out;
  std::vector<int> & fxy(a_fxy);
  int y; int x; int dx; int i; int cxy; int vxy; int new_flow;
  do
  { queue_in = 0; queue_out = 0;
    bfs_queue[queue_in] = source; ++ queue_in;
    for(y=0; n3>y; ++y) { fxy[y] = -1; }
    fxy[source] = -2;
    while(queue_out < queue_in)
    { x = bfs_queue[queue_out]; ++ queue_out;
      dx = static_cast<int>(adj3[x].size());
      for(i=0; dx>i; ++i)
      { y = adj3[x][i].y; cxy = adj3[x][i].c; vxy = adj3[x][i].f;
        if((-1 == fxy[y])&&(vxy<cxy))
        { fxy[y] = adj3[x][i].i; bfs_queue[queue_in] = y; ++queue_in; }
      }
    }
    if(-1!=fxy[sink])
    { new_flow = -1;
      for(y=sink; source != y; y = x)
      { x = adj3[y][fxy[y]].y; i = adj3[y][fxy[y]].i;
        cxy = adj3[x][i].c; vxy = adj3[x][i].f; cxy -= vxy;
        if((-1==new_flow)||(new_flow>cxy)) { new_flow = cxy; } 
      }
      for(y=sink; source != y; y = x)
      { x = adj3[y][fxy[y]].y; i = adj3[y][fxy[y]].i;
        adj3[x][i].f += new_flow; adj3[y][fxy[y]].f -= new_flow;
      }
      flow_value += new_flow;
    }
    else { new_flow = 0; }
  }
  while(0<new_flow);
}

bool
solve()
{ algola a;
  return a.get_ok();
}

int
main()
{ int status;
  bool ok;
  try
  { ok = solve();
    status = ( ok ? 0 : 1 );
  }
  catch ( ... )
  { status = 2; }
  return status;
}