Corso di Informatica 1 (IN110)

Gli esercizi

Testi e soluzioni di alcuni esercizi

Costruzione del grafo complementare

Dato un grafo G(V,E), con |V|=n, espresso mediante liste di adiacenza, generare le liste di adiacenza del grafo G'(V,E') complementare a G, dove E' = {(u,v) tale che (u,v) ∉ E}.

/*
**  complementare.c
**
**  Dato un grafo G(V,E), con |V|=n,  espresso mediante liste di
**  adiacenza, generare le liste di adiacenza del grafo G'(V,E')
**  complementare a G (E' = {(u,v) tale che (u,v) non appartiene
**  ad E).
**
**  Algoritmo:
**    1. calcolo le liste di adiacenza del grafo completo G";
**    2. elimino dalle liste di adiacenza di G" tutti gli spigoli
**       presenti in G ed ottengo G'.
**
**  Marco Liverani (liverani@mat.uniroma3.it) - Gennaio 1999
*/

#include <stdlib.h>
#include <stdio.h>

#define MAX 50


struct nodo {
  int info;
  struct nodo *next;
};


/*
**  leggi_lista
**
**  legge in input una sequenza di numeri interi fino a quando
**  l'utente non digita "-1". I numeri letti vengono man mano
**  memorizzati in una lista. La funzione restituisce un puntatore
**  al primo elemento della lista (l'indirizzo di memoria del
**  primo elemento della lista).
*/

struct nodo *leggi_lista(void) {
  int a;
  struct nodo *p, *primo;

  primo = NULL;
  scanf("%d", &a);
  while (a != -1) {
    p = malloc(sizeof(struct nodo));
    p->info = a;
    p->next = primo;
    primo = p;
    scanf("%d", &a);
  }
  return(primo);
}


/*
**  leggi_grafo
**
**  per ogni vertice del grafo ne legge la lista di adiacenza.
**  Restituisce il numero di vertici.
*/

int leggi_grafo(struct nodo **l) {
  int i, n;

  printf("Numero dei vertici: ");
  scanf("%d", &n);

  for (i=0; i<n; i++) {
    printf("%d: ", i);
    *(l+i) = leggi_lista();
  }

  return(n);
}


/*
** stampa_lista
**
**  visualizza in output una lista di adiacenza; si aspetta come
**  parametro l'indirizzo di memoria (il puntatore) del primo
**  elemento della lista.
*/

void stampa_lista(struct nodo *primo) {
  while (primo != NULL) {
    printf("%d -> ", primo->info);
    primo = primo->next;
  }
  printf("NULL\n");
  return;
}


/*
**  grafo_completo
**
**  costruisce le liste di adiacenza di un grafo completo di n
**  vertici (|V| = n). Aspetta come parametri il numero n di
**  vertici ed il puntatore al primo elemento dell'array dei
**  puntatori ai primi elementi delle liste di adiacenza.
*/

void grafo_completo(int n, struct nodo **lista) {
  int i, j;
  struct nodo *p;

  for (i=0; i<n; i++) {
    *(lista+i) = NULL;
    for (j=0; j<n; j++) {
      if (i != j) {
        p = malloc(sizeof(struct nodo));
        p->info = j;
        p->next = *(lista+i);
        *(lista+i) = p;
      }
    }
  }
  return;
}


/*
**  riduzione
**
**  costruisce il grafo complementare G' di G, riducendo il
**  grafo completo G", eliminando gli spigoli che sono
**  in G. Accetta come parametri il puntatore agli array
**  con le liste di adiacenza di G e di G" ed il numero
**  n di vertici.
*/

void riduzione(int n, struct nodo **lista1, struct nodo **lista2) {
  int i;
  struct nodo *p1, *p2, *prec_p2;

  for (i=0; i<n; i++) {  /* per ogni elemento di G... */
    p1 = *(lista1+i);
    while (p1 != NULL) {  /* scorro la lista di adiacenza dell'elemento fissato */
      prec_p2 = NULL;
      p2 = *(lista2+i);

      /*
      **  salto tutti gli elementi di lista2 che sono diversi
      **  dall'elemento fissato di lista1.
      */

      while (p2->info != p1->info) {
        prec_p2 = p2;
        p2 = p2->next;
      }

      /*
      **  quando esco dal ciclo p2 punta sicuramente ad un elemento
      **  uguale a cio' a cui punta p1. Quindi posso eliminarlo
      **  dalla lista "lista2".
      */

      if (prec_p2 == NULL) {
        *(lista2+i) = p2->next;
      } else {
        prec_p2->next = p2->next;
        free(p2);
        p2 = prec_p2->next;
      }

      p1 = p1->next;
    }
  }
  return;
}


/*
**  main
**
**  la funzione principale richiama tutte le altre.
*/

int main(void) {
  struct nodo *l1[MAX], *l2[MAX];
  int i, n;

  /*
  **  il grafo G viene fornito in input dall'utente
  */

  n = leggi_grafo(&l1[0]);

  /*
  **  il grafo completo G" viene costruito automaticamente
  **  dalla funzione grafo_completo.
  */

  grafo_completo(n, &l2[0]);

  /*
  **  costruisco il grafo complementare G' di G riducendo G"
  */

  riduzione(n, &l1[0], &l2[0]);

  /*
  **  stampo le liste di adiacenza del nuovo grafo
  */

  for (i=0; i<n; i++) {
    printf("%d: ", i);
    stampa_lista(l2[i]);
  }

  return(0);
}


Author: Marco Liverani - Last modified: Monday October 24, 2016 - URI: http://www.mat.uniroma3.it/users/liverani/IN110/complementare.shtml