// -*- c++ -*-
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdlib>

#include <LEDA/graph.h>
#include <LEDA/mcb_matching.h>
#include <LEDA/list.h>

#include <leda_graph_wrapper.h>
#include <list_graph.h>
#include <dimacs.h>
#include <time_measure.h>
#include <edmonds_karp.h>

/**
 * Inicializalja a veletlenszamgeneratort.
 * Figyelem, ez nem jo igazi random szamokhoz,
 * erre ne bizzad a titkaidat!
 */
void random_init()
{
	unsigned int seed = getpid();
	seed |= seed << 15;
	seed ^= time(0);

	srand(seed);
}

/**
 * Egy veletlen int-et ad vissza 0 es m-1 kozott.
 */
int random(int m)
{
	return int( double(m) * rand() / (RAND_MAX + 1.0) );
}

using namespace hugo;

using std::cout; 
using std::cin; 
using std::endl;

int main() {
   leda::graph g;
   typedef LedaGraphWrapper<leda::graph> Graph;
   Graph G(g);
//  typedef ListGraph Graph;
//  Graph G;

  typedef Graph::Node Node;
  typedef Graph::NodeIt NodeIt;  
  typedef Graph::Edge Edge;
  typedef Graph::EdgeIt EdgeIt;
  typedef Graph::OutEdgeIt OutEdgeIt;
  typedef Graph::InEdgeIt InEdgeIt;

  //Node s, t;
  //Graph::EdgeMap<int> cap(G);
  //readDimacsMaxFlow(std::cin, G, s, t, cap);
  std::vector<Node> s_nodes;
  std::vector<Node> t_nodes;

  int a;
  cout << "number of nodes in the first color class=";
  cin >> a; 
  int b;
  cout << "number of nodes in the second color class=";
  cin >> b; 
  int m;
  cout << "number of edges=";
  cin >> m; 
  

  for(int i=0; i<a; ++i) {
    s_nodes.push_back(G.addNode());
  }
  for(int i=0; i<a; ++i) {
    t_nodes.push_back(G.addNode());
  }
  random_init();
  for(int i=0; i<m; ++i) {
    G.addEdge(s_nodes[random(a)], t_nodes[random(b)]);
  }
  
//   G.addEdge(s_nodes[1], t_nodes[5-4]);
//   G.addEdge(s_nodes[1], t_nodes[5-4]);
//   G.addEdge(s_nodes[1], t_nodes[4-4]);
//   G.addEdge(s_nodes[1], t_nodes[4-4]);
//   G.addEdge(s_nodes[2], t_nodes[4-4]);
//   G.addEdge(s_nodes[3], t_nodes[4-4]);

  leda_list<leda_node> A;
  leda_list<leda_node> B;
  Graph::NodeMap<bool> s_map(G); //false
  Graph::NodeMap<bool> t_map(G); //false
  
  for(int i=0; i<a; ++i) { s_map.set(s_nodes[i], true); A+=s_nodes[i]; }
  for(int i=0; i<b; ++i) { t_map.set(t_nodes[i], true); B+=t_nodes[i]; }

//   cout << "bfs and dfs iterator demo on the directed graph" << endl;
//   for(NodeIt n=G.first<NodeIt>(); G.valid(n); G.next(n)) { 
//     cout << G.id(n) << ": ";
//     cout << "out edges: ";
//     for(OutEdgeIt e=G.first<OutEdgeIt>(n); G.valid(e); G.next(e)) 
//       cout << G.id(G.tail(e)) << "->" << G.id(G.head(e)) << " ";
//     cout << "in edges: ";
//     for(InEdgeIt e=G.first<InEdgeIt>(n); G.valid(e); G.next(e)) 
//       cout << G.id(G.tail(e)) << "->" << G.id(G.head(e)) << " ";
//     cout << endl;
//   }


  {
    std::cout << "on-the-fly max bipartite matching (Edmonds-Karp) demo on wrapped leda graph..." << std::endl;
    Graph::EdgeMap<int> flow(G); //0 flow
    Graph::EdgeMap<int> cap(G, 1);

    Timer ts;
    ts.reset();

    MaxMatching<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > max_flow_test(G, s_map, t_map, flow, cap);
    int i=0;
    while (max_flow_test.augmentOnShortestPath()) { 
//       for(EdgeIt e=G.first<EdgeIt>(); G.valid(e); G.next(e))  
// 	std::cout << G.id(G.tail(e)) << "-" << flow.get(e) << "->" << G.id(G.head(e)) << " ";
//       std::cout<<std::endl;
      ++i; 
    }

//     std::cout << "maximum matching: "<< std::endl;
//     for(EdgeIt e=G.first<EdgeIt>(); G.valid(e); G.next(e))  
//       if (flow.get(e))
// 	std::cout << G.id(G.tail(e)) << "-" << flow.get(e) << "->" << G.id(G.head(e)) << " ";
//     std::cout<<std::endl;
//     std::cout << "edges which are not in this maximum matching: "<< std::endl;
//     for(EdgeIt e=G.first<EdgeIt>(); G.valid(e); G.next(e))  
//       if (!flow.get(e))
// 	std::cout << G.id(G.tail(e)) << "-" << flow.get(e) << "->" << G.id(G.head(e)) << " ";
//     std::cout<<std::endl;
    
    std::cout << "elapsed time: " << ts << std::endl;
    std::cout << "number of augmentation phases: " << i << std::endl; 
    std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
  }

//   {
//     std::cout << "on-the-fly max bipartite matching demo (Hopcroft-Karp) on wrapped leda graph..." << std::endl;
//     Graph::EdgeMap<int> flow(G); //0 flow
//     Graph::EdgeMap<int> cap(G, 1);

//     Timer ts;
//     ts.reset();

//     MaxMatching<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > max_flow_test(G, s_map, t_map, flow, cap);
//     int i=0;
//     while (max_flow_test.augmentOnBlockingFlow2()) { 
// //       for(EdgeIt e=G.first<EdgeIt>(); G.valid(e); G.next(e))  
// // 	std::cout << G.id(G.tail(e)) << "-" << flow.get(e) << "->" << G.id(G.head(e)) << " ";
// //       std::cout<<std::endl;
//       ++i; 
//     }

// //     std::cout << "maximum matching: "<< std::endl;
// //     for(EdgeIt e=G.first<EdgeIt>(); G.valid(e); G.next(e))  
// //       if (flow.get(e))
// // 	std::cout << G.id(G.tail(e)) << "-" << flow.get(e) << "->" << G.id(G.head(e)) << " ";
// //     std::cout<<std::endl;
// //     std::cout << "edges which are not in this maximum matching: "<< std::endl;
// //     for(EdgeIt e=G.first<EdgeIt>(); G.valid(e); G.next(e))  
// //       if (!flow.get(e))
// // 	std::cout << G.id(G.tail(e)) << "-" << flow.get(e) << "->" << G.id(G.head(e)) << " ";
// //     std::cout<<std::endl;
    
//     std::cout << "elapsed time: " << ts << std::endl;
//     std::cout << "number of augmentation phases: " << i << std::endl; 
//     std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
//   }

  {
    std::cout << "max bipartite matching (LEDA)..." << std::endl;
    //Graph::EdgeMap<int> flow(G); //0 flow
    //Graph::EdgeMap<int> cap(G, 1);

    leda_node_array<bool> NC(g);

    Timer ts;
    ts.reset();

    //MaxMatching<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > max_flow_test(G, s_map, t_map, flow, cap);
    //int i=0;
    //while (max_flow_test.augmentOnShortestPath()) { ++i; }
    
    //leda_list<leda_edge> l=MAX_CARD_BIPARTITE_MATCHING_HK(g, A, B, NC, false);
    leda_list<leda_edge> l=MAX_CARD_BIPARTITE_MATCHING(g);    
    

//     std::cout << "maximum matching: "<< std::endl;
//     for(EdgeIt e=G.first<EdgeIt>(); G.valid(e); G.next(e))  
//       if (flow.get(e))
// 	std::cout << G.id(G.tail(e)) << "-" << flow.get(e) << "->" << G.id(G.head(e)) << " ";
//     std::cout<<std::endl;
//     std::cout << "edges which are not in this maximum matching: "<< std::endl;
//     for(EdgeIt e=G.first<EdgeIt>(); G.valid(e); G.next(e))  
//       if (!flow.get(e))
// 	std::cout << G.id(G.tail(e)) << "-" << flow.get(e) << "->" << G.id(G.head(e)) << " ";
//     std::cout<<std::endl;
    
    
    std::cout << "elapsed time: " << ts << std::endl;
    //std::cout << "number of augmentation phases: " << i << std::endl; 
    std::cout << "flow value: "<< l.size() << std::endl;
  }
  
  

  return 0;
}
