Advertisement
Guest User

MST Kruskal

a guest
Feb 8th, 2016
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.13 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <assert.h>
  5.  
  6. #define new_list_node() (malloc(sizeof(listnode)))
  7.  
  8. typedef struct _edge {
  9.     int from;
  10.     int to;
  11.     int weight;
  12.     bool is_in_mst;
  13. } edge;
  14.  
  15. typedef struct _node {
  16.     int label;
  17. } node;
  18.  
  19. typedef struct _Lnode {
  20.     node elem;
  21.     int index;
  22.     struct _Lnode *rappr;
  23.     struct _Lnode *next;
  24. } listnode;
  25. /* Crea una nuova lista contenente il nodo passato come primo parametro */
  26. listnode* make_set(node, listnode**);
  27. /* Restituisce il rappresentante dell'insieme (lista) dove compare il nodo passato come terzo parametro */
  28. listnode* find_set(listnode**, int, int);
  29. /* Appende la lista puntata dal primo parametro in fondo alla lista puntata dal secondo e sistema i rappresentanti */
  30. void union_set(listnode**, listnode**, listnode*, listnode*);
  31. /* Funzioni per qsort() */
  32. int compare_edges_lexic(const void *i, const void *j);
  33. int compare_edges(const void *i, const void *j);
  34.  
  35. int main(void) {
  36.     FILE *fin, *fout;
  37.     int i;
  38.     int from, to, weight;
  39.    
  40.     int n, m; // n = #nodi, m = #archi
  41.     int total_weight; // Peso del MST
  42.     edge* edges; // Array degli archi
  43.     node* vertices; // Array dei vertici
  44.     listnode** set; // Array di puntatori a liste (sarebbero gli insiemi disgiunti)
  45.     listnode** tail; // Array di puntatori alla coda delle liste
  46.    
  47.     fin = fopen("input.txt","r");
  48.     fout = fopen("output.txt","w");
  49.    
  50.     assert(fin != NULL && fout != NULL);
  51.    
  52.     assert(2 == fscanf(fin, "%i %i", &n, &m));
  53.    
  54.     vertices = malloc(n * sizeof *vertices);
  55.     edges = malloc(2 * m * sizeof *edges); // 2m, undirected graph
  56.     set = malloc(n * sizeof *set); // Disjoint-set
  57.     tail = malloc(n * sizeof *tail); // Puntatori alle code delle liste
  58.     assert(vertices != NULL && edges != NULL && set != NULL && tail != NULL);
  59.     for(i=0;i<n;i++)
  60.         vertices[i].label = -1;
  61.    
  62.     for(i=0;i<m;i++) {
  63.         assert(3 == fscanf(fin, "%i %i %i", &from, &to, &weight));
  64.         edges[i].from = from;
  65.         edges[i].to = to;
  66.         edges[i].weight = weight;
  67.         edges[i].is_in_mst = false;
  68.         /* Arco contrario, perché è non orientato */
  69.         edges[2*m-i-1].from = to;
  70.         edges[2*m-i-1].to = from;
  71.         edges[2*m-i-1].weight = weight;
  72.         edges[2*m-i-1].is_in_mst = false;
  73.         /* Aggiungo il vertice, se non c'è già */
  74.         if(vertices[from-1].label == -1)
  75.             vertices[from-1].label = from;
  76.         if(vertices[to-1].label == -1)
  77.             vertices[to-1].label = to;
  78.     }
  79.    
  80.     /* ALGORITMO DI KRUSKAL */
  81.    
  82.     for(i=0;i<n;i++) {
  83.         // MAKE-SET(v)
  84.         set[i] = make_set(vertices[i], &tail[i]); // Imposto anche la coda
  85.     }
  86.    
  87.     qsort(edges, 2*m, sizeof(edge), compare_edges); // Ordino gli archi per peso crescente
  88.     total_weight = 0;
  89.    
  90.     for(i=0;i<2*m;i+=2) {
  91.         listnode *rappr_u = find_set(set, n, edges[i].from), *rappr_v = find_set(set, n, edges[i].to);
  92.         if(rappr_u != rappr_v) { // Se sono in due alberi diversi
  93.             edges[i].is_in_mst = true; // Prendo l'arco
  94.             total_weight += edges[i].weight;
  95.             union_set(set, tail, rappr_u, rappr_v); // Unisco i due alberi in un unico albero
  96.         }
  97.        
  98.     }
  99.    
  100.     fprintf(fout, "%i\n", total_weight);
  101.     qsort(edges, 2*m, sizeof(edge), compare_edges_lexic); // Ordino gli archi in ordine lessicografico
  102.     for(i=0;i<2*m;i++)
  103.         if(edges[i].is_in_mst)
  104.             fprintf(fout, "%i %i\n", edges[i].from, edges[i].to);
  105.    
  106.     /* CLEANUP */
  107.     fclose(fin);
  108.     fclose(fout);
  109.     free(vertices);
  110.     free(edges);
  111.     for(i=0;i<n;i++) {
  112.         listnode *s = set[i];
  113.         while(s != NULL) {
  114.             listnode *tmp = s;
  115.             s = s->next;
  116.             free(tmp);
  117.         }
  118.     }
  119.     free(set);
  120.     free(tail);
  121.    
  122.     return 0;
  123. }
  124.  
  125. listnode* make_set(node v, listnode** tail) {
  126.     listnode *new = new_list_node();
  127.     new->elem = v;
  128.     new->rappr = new;
  129.     new->index = v.label-1;
  130.     new->next = NULL;
  131.    
  132.     *tail = new;
  133.     return new;
  134. }
  135.  
  136. listnode* find_set(listnode** set, int n, int label) {
  137.     int i;
  138.     // NAIF
  139.     for(i=0;i<n;i++) { // Scorro tutti i set
  140.         listnode *curr = set[i];
  141.         while(curr != NULL) { // Scorro tutte le liste di tutti i set
  142.             if(curr->elem.label == label) { // Se lo trovo..
  143.                                             //printf("Ho trovato il rappr di %i che è %i\n",label,curr->rappr->elem.label);
  144.                                             /* aspetta(); */
  145.                 return curr->rappr; // Restituisco il rappresentante dell'insieme
  146.             }
  147.             curr = curr->next;
  148.         }
  149.     }
  150.     return NULL;
  151. }
  152.  
  153. // Appende la lista di U in fondo alla lista di V
  154. void union_set(listnode** set, listnode** tail, listnode* u, listnode* v) {
  155.     tail[v->elem.label-1]->next = u;
  156.     u->rappr = set[v->elem.label-1];
  157.     /* Sistemo tutti i rappresentanti di u */
  158.     listnode* tmp = u->next;
  159.     while(tmp != NULL) {
  160.         tmp->rappr = set[v->elem.label-1];
  161.         tmp = tmp->next;
  162.     }
  163.    
  164.     set[u->elem.label-1] = NULL;
  165.     tail[v->elem.label-1] = tail[u->elem.label-1];
  166. }
  167.  
  168. /* Relazione di ordinamento lessicografico degli archi */
  169. int compare_edges_lexic(const void *i, const void *j) {
  170.     int diff_from = ((edge *) (i))->from - ((edge *) (j))->from;
  171.     if(diff_from == 0)
  172.         return ((edge *) (i))->to - ((edge *) (j))->to;
  173.     return diff_from;
  174. }
  175.  
  176. /* Relazione di ordinamento in base al peso degli archi */
  177. int compare_edges(const void *i, const void *j) {
  178.     int diff_weight = ((edge *) (i))->weight - ((edge *) (j))->weight;
  179.     if(diff_weight == 0)
  180.         return compare_edges_lexic(i, j);
  181.     return diff_weight;
  182. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement