\begin{document} \section{Rand.H} <>= // File: Rand.H // Last Revision: 23-Mar-2001 // Description: functions for the generation of random values. // programmer: Romeo Rizzi. // rrizzi@rtm.science.unitn.it // // responsible: Roberto Battiti. // battiti@science.unitn.it // // group: LEA (Laboratory for Experimental Algorithmics). // http://rtm.science.unitn.it/ // // Note: The two functions myrand() and smyrand() were written by Dell'Amico // using the portable pseudorandom generator RnG (see below). #ifndef _RAND_H #define _RAND_H float myrand(); float smyrand(int seed); int lprand(); int sprand (int seed); int dado(int num_facce); // returns an integer in [0, ... , num_facce-1] uniformly at random. #endif @ \section{Rand.cpp} <>= // File: Rand.ccp // Last Revision: 23-Mar-2001 // Description: functions for the generation of random values. // programmer: Romeo Rizzi. // rrizzi@rtm.science.unitn.it // // responsible: Roberto Battiti. // battiti@science.unitn.it // // group: LEA (Laboratory for Experimental Algorithmics). // http://rtm.science.unitn.it/ // // Note: The two functions myrand() and smyrand() were written by Dell'Amico // using the portable pseudorandom generator RnG (see below). #include "Rand.H" #define PRANDMAX 1000000000 int dmxa, dmxb, dmxarr[55]; float myrand() { return ((float)lprand()) / PRANDMAX; } float smyrand(int seed) { return (float) sprand(seed); } int dado(int num_facce) { return (int) (num_facce * myrand()); } /* This file contains a set of c-language functions for generating uniform integers. This is a COMPLETELY PORTABLE generator. it will give iDEnTiCAL sequences of random numbers for any architecture with at least 30-bit integers, regardless of the integer representation, MAXinT value, or roundoff/truncation method, etc. This Truly Remarkable RnG is described more fully in j. Bentley's column, ``The Software Exploratorium '' to appear in Unix Review in 1991. it is based on one in knuth, Vol 2, Section 3.2.2 (Algorithm A) This is a little driver program so you can test the code. Giving input parameters: 0 3 1 should produce 921674862 250065336 377506581 Giving 1000000 1 2 should produce 572653995 void main() { int i,j,n,m,seed; scanf("%d %d %d",&m,&n,&seed); i = sprand(seed); for(i=0; i< m;i++) j = lprand(); for (i=0; i< n; i++) printf("\n%ld",lprand()); } */ // ---------RnG--------------------- // Returns long ints from the // range 0...PRANDMAX-1 int lprand() { dmxa --; if (dmxa < 0) dmxa = 54; dmxb --; if (dmxb < 0) dmxb = 54; int t = dmxarr[dmxa] - dmxarr[dmxb]; return dmxarr[dmxa] = ( (t < 0) ? t + PRANDMAX : t); } //-----------RnG initializer------------ // Call once before using lprand int sprand (int seed) { int i, ii, last, next; dmxarr[0] = last = seed; next = 1; for (i=1; i< 55; i++ ) { ii = 21 * i % 55; dmxarr[ii] = next; next = last - next; if (next < 0) next += PRANDMAX; last = dmxarr[ii]; } dmxa = 0; dmxb = 24; for(i = 0; i<= 164; i++) lprand(); return seed; } @ \section{heap.H} <>= #include template inline bool less(const T& a, const T& b) { return (a < b); } inline bool less(const char* a, const char* b) { return (strcmp(a, b) < 0 ? true : false); } template inline void swap(T& a, T& b) { T temp(a); a = b; b = temp; } template class heap { private: size_t size; size_t length; T* a; public: heap(size_t initial_size = 10): size(initial_size), length(0), a(new T[initial_size]) { } heap(T array[], size_t nUsed):a(array), size(sizeof(array)), length(nUsed) { } virtual ~heap() { delete[] a; } size_t get_used() { return length; } bool is_empty() { return (length == 0); } T min() { if (is_empty()) { throw(3); } return a[0]; } void del_min() { a[0] = a[length - 1]; --length; movedown(0); } void movedown(size_t pos) { T moving_elem = a[pos]; size_t iSon, iSonDx; for(;;) { iSon = (pos << 1) + 1; if((iSonDx = iSon + 1) < length && less(a[iSonDx], a[iSon])) ++iSon; if(iSon < length && less(a[iSon], moving_elem)) { a[pos] = a[iSon]; pos = iSon; } else { a[pos] = moving_elem; return; } } } void insert(const T& elem) { if (length == size) { size_t newsize = size * 2 + 1; T* b = new T[newsize]; memcpy((void*)a, (void*)b, sizeof(T)*size); swap(a, b); size = newsize; delete[] b; } a[length] = elem; moveup(length); ++length; } void moveup(size_t pos) { T moving_elem = a[pos]; int father; while((father = (int)(pos - 1) >> 1) >= 0 && less(moving_elem, a[father])) { a[pos] = a[father]; pos = father; } a[pos] = moving_elem; } void touch(size_t pos) { if(pos > 0 && pos < length && less(a[pos], a[(pos - 1) >> 1])) moveup(pos); else movedown(pos); } }; @ \section{wGraph.H} <>= /* File: wGraph.H * Last Revision: 2-Apr-2001 * Description: a data type for weighted graphs. * a weighted graph is a graph G=(V,E) with integer weights on the edges. * * author: Romeo Rizzi. * romeo@science.unitn.it * * Classes declared: wGraph * * The class wGraph implements: * 1) The data structure storing a given weighted graph, * 2) The methods for quering this data structure, * 3) The methods to generate "DSJ_U" and "DSJ_G" graphs (see below), * 4) The methods for loading the input graph from a file. * (natural extension of DIMACS format, or of JOHNSON format). */ #ifndef _W_GRAPH_H #define _W_GRAPH_H #include #include #include "Rand.H" #define MAX_NODES 10000 #define MAX_W 100 #define DIMACS 1 #define BINARY_DIMACS 2 #define JOHNSON 3 #define SQR(x) ( (x)*(x) ) enum graph_enum { DSJ_U, DSJ_G}; /* We generate two kinds of graphs: * DSJ_U: Each node is put in the plane and receives two random coordinates. * Two nodes u and v are then connected by an edge uv, if and only * if their distance does not exceed a given constant. * In case the edge exists, then its weight is choosen uniformly * at random in the interval [1, ..., MAX_W]. * DSJ_G: Random weighted graphs where the probability that there exists * an edge between any two nodes is a constant. * In case the edge exists, then its weight is choosen uniformly * at random in the interval [1, ..., MAX_W]. * Thus the expected degree of any vertex is a constant. * Such graphs are indeed characterized by their expected degree. * * Note: G and U graphs are extensions of the unweighted graphs * produced in the class Graph or as by Dell'Amico - Maffioli. * Starting from a same seed we obtain the same support graph * as in the class Graph or as Dell'Amico - Maffioli. */ class Graph { /* A graph G has n nodes and m edges. * We number the nodes of G as: 1, ... ,n. * * Data Structures: * * 1) THE ADJACENCY MATRIX: adj_M * adj_M [u][v] == 1 if edge (u,v) exists; 0 otherwise. * * 2) THE MATRIX of WEIGHTS: W * W [u][v] gives the weight of edge (u,v) when such an edge exists. * * 3) THE SEQUENCE OF NEIGHBORS: list_of_neighbors and first_nei * list_of_neighbors has the following structure: * * | * first_nei[i] * * first_nei[i] = the position in list_of_neighbors[] of the first neighbor of vertex i * * The neighbors of vertex i are: * list_of_neighbors[first_nei[i]], list_of_neighbors[first_nei[i]+1],...,list_of_neighbors[first_nei[i+1]-1]). * * NOTE: (a detail in our implementation of list_of_neighbors) * Between the neighbors of node i and the neighbors * of node (i+1) we put a 0 as separetor. * This trick allows for a faster scan of the neighbors of any node. * (See procedures first_neighbor(node u) and next_neighbor() below. */ int n_nodes; // number of nodes. int n_edges; // number of edges. int half_n_nodes; // half_n_nodes = (n_nodes /2). int **adj_M; int **W; // SEQUENCE OF NEIGHBORS: int *first_nei; int *list_of_neighbors; int *deg; // the degree array of nodes. (degree= number of neighbors). int max_deg; // the maximum degree of a node. int *neighbor_pos; // used to scan the neighbor of a node. void Make_Star_DataStructure(); // derives "list_of_neighbors" and "first_nei" from "adj_M". // ALLOCATING THE ADJACENCY MATRIX "adj_M". void allocate_adj_M(); // ALLOCATING THE MATRIX OF WEIGHTS "W". void allocate_W(); // STORING RANDOM WEIGHTS INTO MATRIX "W". void random_W(); // GENERATING "DSJ_U" and "DSJ_G" GRAPHS: int iseed; // seed to random generate graphs DSJ_U or DSJ_G. double density, distance; void generate_G_graph(double density); /* Instantiates a graph of type "G". * assumes "adj_M" having been allocated before the call. * At termination "adj_M" is the adjacency matrix of the generated graph. * However the star data structures are not yet initialized at termination * and will be derived from "adj_M" in a second phase by the method "Make_Star_DataStructure()". */ void generate_U_graph(double distance); /* Instantiates a graph of type "U". * assumes "adj_M" having been allocated before the call. * At termination "adj_M" is the adjacency matrix of the generated graph. * However the star data structures are not yet initialized at termination * and will be derived from "adj_M" in a second phase by the method "Make_Star_DataStructure()". */ // LOADING UP A GRAPH FROM A FILE: void dimacs_input(const char *file); // inputs a graph in the binary (compressed) dimacs format. // see URL: void johnson_input(const char *file); // inputs a graph in the johnson format. // see URL: public: Graph (graph_enum gen, int n, double expected_deg, int np, int seed=1); /* Generates a graph of type with nodes. * is the seed to random generate the graph: different calls with * the same (and the same ) produce identical graphs. * (in fact, for a given pair (, ), we produce the same graph * as Dell'Amico-Maffioli generator). * is the expected degree of the random graph to be instantiated. * is the problem number and is output after the graph * has been generated together with other informations about the graph. */ Graph (const int format, const char *file); // Creates a graph by loading it from a in a given . ~Graph(); void write(const int format, const char *file); // saves the graph on a according to the specifyied // (useful for conversions, of no use for the search algorithms). int n() const // returns the number of nodes. { return n_nodes; } int m() const // returns the number of edges. { return n_edges; } int half_n() const // returns half the number of nodes. { return half_n_nodes; } int edge(int u, int v) const // returns 1 if nodes u and v are adjacent. {return adj_M [u][v]; } // returns 0 otherwise. // note: edge(x,x) == 0, no self-connection. int weight(int u, int v) const // returns the weight of edge uv. {return W [u][v]; } // the returned value is not defined // if u and v are not adjacent. int max_degree() // returns the maximum degree. { return max_deg; } int degree(int v) const // returns the degree of node v. { return deg[v]; } int first_neighbor(int v); // returns 0 if no neighbor. int next_neighbor(); // returns 0 if no next neighbor. int size_of_cut(const int *x); // returns the number of edges whose // endpoints have different x[] values. }; inline int Graph::next_neighbor() // returns 0 if no next neighbor. { return *(neighbor_pos ++); } inline int Graph::first_neighbor(int v) { // returns 0 if no neighbor. neighbor_pos = list_of_neighbors + first_nei[v]; return next_neighbor(); } #endif @ \section{wGraph.cpp} <>= /* File: wGraph.cpp * Last Revision: 2-Apr-2001 * Description: this file contains the definition of the class wGraph * as declared in the file wGraph.H (see file wGraph.H to get more insight). * * programmer: Romeo Rizzi. * rrizzi@rtm.science.unitn.it * * Classes defined: wGraph */ #include "wGraph.H" #include Graph::Graph(graph_enum gen, int num_nodi, double expected_deg, int np, int seed) { n_nodes = num_nodi; n_edges = 0; half_n_nodes = num_nodi/2; // Initialize the random generator and other parameters to generate the graph. iseed = (long)(n_nodes *131 + expected_deg *101 + np *191 + seed ) % 32767; smyrand(iseed); density = (double) expected_deg / (n_nodes - 1) ; distance = sqrt(expected_deg / (n_nodes * 3.141592653589793238)); // Allocate the adjacency matrix "adj_M [u][v]". allocate_adj_M(); // Allocate the matrix of weights "W [u][v]". allocate_W(); // Generate a type (gen) graph. Generate the adjacency matrix adj_M[u][v]. switch (gen) { case DSJ_G : generate_G_graph(density); break; case DSJ_U : generate_U_graph(distance); break; } Make_Star_DataStructure(); cout << "\n\nN= " << n_nodes << " Nu= " << expected_deg << " Tipo grafo= " << gen << " N.lati= " << n_edges << " Seed= " << iseed << " N.problema= " << np << endl; } void Graph::allocate_adj_M() { adj_M = new int*[n_nodes] -1; for (int i = n_nodes; i; i--) { adj_M[i] = new int[n_nodes] -1; for(int j = n_nodes; j; j--) adj_M[i][j] = 0; } } void Graph::allocate_W() { W = new int*[n_nodes] -1; for (int i = n_nodes; i; i--) { W[i] = new int[n_nodes] -1; for(int j = n_nodes; j; j--) W[i][j] = 0; } } Graph::~Graph() { for(int i = n_nodes; i; i--) { delete [] (adj_M[i] +1); delete [] (W +1); } delete [] (adj_M +1); delete [] (W +1); delete [] (first_nei +1); delete [] (list_of_neighbors +1); delete [] (deg +1); } void Graph::Make_Star_DataStructure() { deg = new int[n_nodes] -1; max_deg = 0; first_nei = new int[n_nodes] -1; list_of_neighbors = new int[2*n_edges + n_nodes] -1; int pos = 1; for(int i = n_nodes; i; i--) { first_nei[i] = pos; for(int j = n_nodes; j; j--) if (adj_M[i][j]) list_of_neighbors[ pos++ ] = j; deg[i] = pos - first_nei[i]; list_of_neighbors[ pos++ ] = 0; if( deg[i] > max_deg ) max_deg = deg[i]; } } // generate random weights and store them into matrix W void Graph::random_W() { for(int i = 1; i < n_nodes; i++) for(int j = n_nodes; j > i; j--) if ( adj_M[i][j] ) W[i][j] = W[j][i] = 1+dado(MAX_W); } // generate G graphs void Graph::generate_G_graph(double density) { for(int i = 1; i < n_nodes; i++) for(int j = n_nodes; j > i; j--) if ( myrand() < density ) { adj_M[i][j] = adj_M[j][i] = 1; n_edges ++; } random_W(); } // generate U graphs void Graph::generate_U_graph(double distance) { int i, j; double *x, *y; x = new double[n_nodes +1]; y = new double[n_nodes +1]; for(i = n_nodes; i; i--) { x[i] = myrand(); y[i] = myrand(); } for(i = n_nodes; i; i--) for(j = n_nodes; j > i; j--) if(SQR( x[i] -x[j] ) + SQR( y[i] -y[j] ) < SQR(distance)) { adj_M[i][j] = adj_M[j][i] = 1; n_edges ++; } delete [] x; delete [] y; random_W(); } void Graph::dimacs_input(const char *file) { ifstream in(file); if (!in.good()) { cerr << "err: input_graph: Input graph does not exist." << endl; exit(1); } char first_char_of_line, pippo[1000]; in.get(first_char_of_line); while(first_char_of_line != 'p') { in.getline(pippo,1000); in.get(first_char_of_line); } in >> pippo >> n_nodes >> n_edges; in.getline(pippo,1000); // Allocate the adjacency matrix "adj_M [u][v]". allocate_adj_M(); // Allocate the matrix of weights "W [u][v]". allocate_W(); int i, j, w, num_arcs = n_edges; while(num_arcs--) { in.get(first_char_of_line); while(first_char_of_line != 'e') { in.getline(pippo,1000); in.get(first_char_of_line); } in >> i >> j >> w; in.getline(pippo,1000); adj_M[i][j] = 1; adj_M[j][i] = 1; W[i][j] = w; W[j][i] = w; } half_n_nodes = n_nodes /2; } void Graph::johnson_input(const char *file) { ifstream in(file); if (!in.good()) { cerr << "err: input_graph: Input graph does not exist." << endl; exit(1); } int max_node = 0, num_arc = 0, node_of_line, degree, neighbor, w; char pippo[50]; do { in >> node_of_line >> pippo >> degree; if (node_of_line > max_node) max_node = node_of_line; num_arc += degree; for (; degree > 0; degree--) { in >> neighbor; if (neighbor > max_node) max_node = neighbor; } } while(in); n_nodes = max_node; n_edges = num_arc /2; half_n_nodes = n_nodes /2; // Allocate the adjacency matrix "adj_M [u][v]". allocate_adj_M(); // Allocate the matrix of weights "W [u][v]". allocate_W(); in.close(); in.open(file); do { in >> node_of_line >> pippo >> degree; for (; degree > 0; degree--) { in >> neighbor >> w; adj_M[node_of_line][neighbor] = 1; adj_M[neighbor][node_of_line] = 1; W[node_of_line][neighbor] = w; W[neighbor][node_of_line] = w; } } while(in); in.close(); } Graph::Graph(const int format, const char *file) { switch (format) { case DIMACS : dimacs_input(file); break; case JOHNSON : johnson_input(file); break; default: cerr << "err: input_graph: " << "We input only graphs in DIMACS or JOHNSON format." << endl; exit(1); } Make_Star_DataStructure(); } void Graph::write(const int format, const char *file) { if (format != DIMACS) { cerr << "err: output_graph: " << "We output only graphs in DIMACS format." << endl; exit(1); } ofstream output(file); output << "p gp " << n_nodes << " " << n_edges << endl; for(int i = 1; i < n_nodes; i++) for(int j = i+1; j <= n_nodes; j++) if (adj_M[i][j]) output << "e " << i << " " << j << " " << W[i][j] << endl; output.close(); } int Graph::size_of_cut(const int *x) // returns the number of edges whose // endpoints have different x[] values. { int size = 0; for(int node = n_nodes; node; node--) { int x_node = x[node]; neighbor_pos = list_of_neighbors + first_nei[node]; while(*neighbor_pos > node) if(x[*(neighbor_pos ++)] != x_node) ++size; } return size; } @ \section{kruskal.cpp} <>= #include #include "wGraph.H" #include "heap.H" // lo heap di Lorenzo Dematte void usageSyntaxHelp(int argc, char **argv); struct elem { int father; int card; }; class setUnion { int n; // cardinality of the ground set. elem * eqClass; public: setUnion(int n) { eqClass = new elem[n+1]; for(int i = 1; i <= n; i++) { eqClass[i].father = i; eqClass[i].card = 1; } } ~setUnion() { delete eqClass; } void Union(int i, int j) { if(eqClass[j].card < eqClass[i].card) { int swap = i; i = j; j = swap; } eqClass[i].father = j; eqClass[j].card = eqClass [j].card + eqClass [i].card ; eqClass[i].card = 0; } int find(int i) { while(eqClass[i].card == 0) i = eqClass[i].father; return i; } }; struct edge { public: int node_A; int node_B; int weight; }; inline bool less(const edge a, const edge b) { return (a.weight < b.weight); } int main(int argc, char **argv) { usageSyntaxHelp(argc, argv); Graph* G = new Graph(DIMACS, argv[1]); heap HeapOfEdges; for(int v = G->n(); v; v--) for(int nei = G->first_neighbor(v); nei; nei = G->next_neighbor()) if(nei > v) { edge e; e.node_A = v; e.node_B = nei; e.weight = G->weight(v,nei); HeapOfEdges.insert(e); } setUnion components(G->n()); int cost = 0; while (!HeapOfEdges.is_empty()) { edge e = HeapOfEdges.min(); HeapOfEdges.del_min(); int component_A = components.find(e.node_A); int component_B = components.find(e.node_B); if(component_A != component_B) { cost += e.weight; cout << "arco (" << e.node_A << "," << e.node_B << ")" << endl; components.Union(component_A, component_B); } } delete G; exit(0); } void usageSyntaxHelp(int argc, char **argv) { if(argc != 2) { exit(1); } } @ \end{document}