Domanda Risolto grafo ciclico in c

Stato
Discussione chiusa ad ulteriori risposte.

sara20

Utente Silver
6 Febbraio 2020
116
29
1
54
Buon pomeriggio devo realizzare il seguente programma in c con grafi orientati : Dato un grafo G orientato rappresentato con liste di adiacenza, scrivere una funzione che verifichi se ci siano cicli nel grafo e, in caso ne esista uno, elimini l’arco che lo crea. Posto il codice che ho iniziato a realizzare
Il MAIN
C:
#include <stdio.h>
#include "Graph.h"
#include "List.h"

int main() {
       int n,e,i,v,u;
        Graph G =NULL;
    
     printf("\nEnter the number of vertices - ");
     scanf("%d",&n);

     G = initGraph(n);
     printf("\nEnter the number of edges - ");
     scanf("%d",&e);

     printf("\nVertices are - ");
     for(i=1;i<n;i++)
        printf("%d ",i);


     printf("\nEnter the edges separated by space - ");
     for(i=1;i<e;i++)
     {
         scanf("%d%d",&v,&u);
         addEdge(G,v,u);
        
     }
    
     printGraph(G);
     DFS(G, 2);

     printf("\n\n");
    return 0;
}
Graph.h
C:
#ifndef Graph_h
#define Graph_h
#include <stdio.h>
#include "List.h"

struct TGraph {
    List *adj;
    int* visited;
    struct TList** adjLists;
    int nodes_count;
};

typedef struct TGraph* Graph;

// Crea un grafo in modo random con nodes nodi
Graph randomGraph(int nodes);

// Dealloca l'intero grafo
void freeGraph(Graph G);

// Inizializza un nuovo grafo vuoto specificando in ingresso quanti nodi saranno nel grafo
Graph initGraph(int nodes_count);

// Stampa il grafo
void printGraph(Graph G);

// Aggiunge un arco, specificando sorgente, target e peso
void addEdge(Graph G, int source, int target);

// Rimuovi un arco specificando sorgente e target,restituisce la lista degli archi modifcata
List removeEdge(Graph G, int source, int target);

// Aggiungi un nodo
void addNode(Graph G);

// Rimuovi un nodo dal grafo, sistemando gli indici e riallocando la memoria
void removeNode(Graph G, int node_to_remove);

List checkListRemoval(List L, int node_to_remove);

// Crea un nuovo grafo e lo popola in base alla scelta effettuata dal menu
Graph graphCreationMenu(int n);

// Menu per la modifica e gestione dei grafi
void graphEditorMenu(Graph);

#endif /* Graph_h */
Graph.c
C:
#include "Graph.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include "Graph.h"

Graph initGraph(int nodes_count) {
    Graph G = (Graph)malloc(sizeof(struct TGraph));
    G->adj = (List *)calloc(nodes_count, sizeof(List));
    G->nodes_count = nodes_count;
    return G;
}

void freeGraph(Graph G) {
    if (G != NULL) {
        if (G->nodes_count > 0) {
            int i = 0;
            for (i = 0; i < G->nodes_count; i++) {
                freeList(G->adj[i]);
            }
        }
        free(G);
    }
}

void printGraphAux(Graph G) {
    if (G != NULL) {
        int x = 0;
        for (x = 0; x < G->nodes_count; x++) {
            printf("%d -> ", x);
            printList(G->adj[x]);
            printf("\n");
        }
    }
}

void printGraph(Graph G) {
    printGraphAux(G);
    printf("\n\n");
}

void addEdge(Graph G, int source, int target) {
    assert(G != NULL);
    assert(source < G->nodes_count);
    assert(target < G->nodes_count);
    if (source != target) {
        G->adj[source] = appendNodeList(G->adj[source], target);
    }
    
}


List removeEdge(Graph G, int source, int target) {
    assert(G != NULL);
    assert(source < G->nodes_count);
    assert(target < G->nodes_count);
    if (source != target) {
        G->adj[source] = removeNodeList(G->adj[source], target);
    }
    return G->adj[source];
}


void addNode(Graph G) {
    if (G != NULL) {
        List * old=G->adj;
        int i=0;
        //G->adj = (List *)realloc(G->adj, (G->nodes_count+1) * sizeof(List));
        G->adj = (List *)malloc((G->nodes_count+1) * sizeof(List));
        for(i=0;i<G->nodes_count;i++)
            G->adj[i]=old[i];
        G->nodes_count += 1;
        G->adj[G->nodes_count-1] = NULL;
    }
}


void removeNode(Graph G, int node_to_remove) {
    if (G != NULL) {
        int i = 0;
        int x = 0;
        List *tmp = G->adj;
        G->adj = (List *)calloc(G->nodes_count-1, sizeof(List));
        for (i = 0; i < G->nodes_count; i++) {
            if (i != node_to_remove) {
                G->adj[x] = checkListRemoval(tmp[i], node_to_remove);
                x++;
            } else {
                freeList(tmp[i]);
            }
        }
        free(tmp);
        G->nodes_count -= 1;
    }
}


List checkListRemoval(List L, int node_to_remove) {
    if (L != NULL) {
        L->next = checkListRemoval(L->next, node_to_remove);
        if (L->target == node_to_remove) {
            List tmp = L->next;
            free(L);
            return tmp;
        } else if (L->target > node_to_remove) {
            L->target -= 1;
        }
    }
    return L;
}


// DFS algo
void DFS(struct TGraph* graph, int vertex) {
  struct TList* adjList = graph->adjLists[vertex];
  struct TList* temp = adjList;

  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  while (temp != NULL) {
    int connectedVertex = temp->vertex;

    if (graph->visited[connectedVertex] == 0) {
      DFS(graph, connectedVertex);
    }
    temp = temp->next;
  }
}
List.h
C:
#ifndef List_h
#define List_h

#include <stdio.h>
struct TList {
    int target;
     int vertex;
    struct TList* next;
};

typedef struct TList* List;

// Inizializza un nuovo nodo
List initNodeList(int info);



// Aggiunge un nodo alla fine della lista
// controllandone l'esistenza
// La funzione ritorna sempre la testa della lista
List appendNodeList(List L, int target);

// Aggiunge un nodo in testa alla lista
// senza controllare l'esistenza
// La funzione ritorna sempre la testa della lista
List addNodeList(List L, int target);

// Rimuove solo un occorrenza di un nodo con il target specificato
// dalla lista
// La funzione ritorna sempre la testa della lista
List removeNodeList(List L, int target);

// Dealloca la lista interamente
void freeList(List L);

// Stampa la lista
void printList(List L);

#endif /* List_h */
List.c
C:
#include "List.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "List.h"

List initNodeList(int info) {
    List L = (List)malloc(sizeof(struct TList));
    L->target = info;
    L->next = NULL;
    return L;
}


List appendNodeList(List L, int target) {
    if (L != NULL) {
        if (L->target != target) {
            L->next = appendNodeList(L->next, target);
        }
    } else {
        L = initNodeList(target);
    }
    return L;
}

List addNodeHead(List L, int target, int peso) {
    if (L != NULL) {
        List G = (List )malloc(sizeof(struct TList));
        G->target = target;
        G->next = L;
        return G;
    }
    return initNodeList(target);
}


List removeNodeList(List L, int target) {
    if (L != NULL) {
        if (L->target == target) {
            List tmp = L->next;
            free(L);
            return tmp;
        }
        L->next = removeNodeList(L->next, target);
    }
    return L;
}


void freeList(List L) {
    if (L != NULL) {
        freeList(L->next);
        free(L);
    }
}


void printList(List L) {
    if (L != NULL) {
        printf(" %d ", L->target);
        printList(L->next);
    }
}
Non riesco a capire come applicare la hfs per determinare se nel grafo ci sono cicli
 
Premesso che l'unica cosa che ho letto è la tua implementazione dell'algoritmo DFS, io direi che basta fare questo:
C:
void DFS(struct TGraph* graph, int vertex) {
  struct TList* adjList = graph->adjLists[vertex];
  struct TList* temp = adjList;

  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  while (temp != NULL) {
    int connectedVertex = temp->vertex;

    if (graph->visited[connectedVertex] == 0) {
      DFS(graph, connectedVertex);
    } else {
        printf("The edge %d -> %d form a cycle\n", vertex, connectedVertex); // unica riga che ho aggiunto
    }
    temp = temp->next;
  }
}
Prova a fare qualche test per vedere se ti quaglia tutto, poi prova a eliminare il ciclo rimuovendo l'elemento incriminato (connectedVertex) dalla lista di adiacenza del nodo attualmente visitato (temp).
 
Premesso che l'unica cosa che ho letto è la tua implementazione dell'algoritmo DFS, io direi che basta fare questo:
C:
void DFS(struct TGraph* graph, int vertex) {
  struct TList* adjList = graph->adjLists[vertex];
  struct TList* temp = adjList;

  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  while (temp != NULL) {
    int connectedVertex = temp->vertex;

    if (graph->visited[connectedVertex] == 0) {
      DFS(graph, connectedVertex);
    } else {
        printf("The edge %d -> %d form a cycle\n", vertex, connectedVertex); // unica riga che ho aggiunto
    }
    temp = temp->next;
  }
}
Prova a fare qualche test per vedere se ti quaglia tutto, poi prova a eliminare il ciclo rimuovendo l'elemento incriminato (connectedVertex) dalla lista di adiacenza del nodo attualmente visitato (temp).
Si però nel main dovrei mettere dfs(g,vertice)...come vertice cosa metto?
 
Si però nel main dovrei mettere dfs(g,vertice)...come vertice cosa metto?
Senza fare assunzioni sul grafo, puoi fare un for per iterare tutti i possibili valori da 0 a nodes_count (escluso). A questo punto però dovresti cambiare DFS in questo modo:
C:
void DFS(struct TGraph* graph, int vertex) {
  if (graph->visited[vertex]) return; // already visited, do nothing

  struct TList* adjList = graph->adjLists[vertex];
  struct TList* temp = adjList;
  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  while (temp != NULL) {
    int connectedVertex = temp->vertex;

    if (graph->visited[connectedVertex] != 0) // cycle detected
        printf("The edge %d -> %d form a cycle\n", vertex, connectedVertex); 

    temp = temp->next;
  }
}
Se il grafo è fortemente connesso (strongly connected) puoi risparmiarti il for e mettere un valore qualunque (diciamo 0). In ogni caso l'efficienza dell'algoritmo non cambia (O(V+E)) e continui a visitare ogni nodo una sola volta.

P.S. Non sto testando il codice che ti sto scrivendo, quindi pensaci due volte prima di fare copy&paste e prendere tutto per buono. Fai i dovuti test.
 
Senza fare assunzioni sul grafo, puoi fare un for per iterare tutti i possibili valori da 0 a nodes_count (escluso). A questo punto però dovresti cambiare DFS in questo modo:
C:
void DFS(struct TGraph* graph, int vertex) {
  if (graph->visited[vertex]) return; // already visited, do nothing

  struct TList* adjList = graph->adjLists[vertex];
  struct TList* temp = adjList;
  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  while (temp != NULL) {
    int connectedVertex = temp->vertex;

    if (graph->visited[connectedVertex] != 0) // cycle detected
        printf("The edge %d -> %d form a cycle\n", vertex, connectedVertex);

    temp = temp->next;
  }
}
Se il grafo è fortemente connesso (strongly connected) puoi risparmiarti il for e mettere un valore qualunque (diciamo 0). In ogni caso l'efficienza dell'algoritmo non cambia (O(V+E)) e continui a visitare ogni nodo una sola volta.

P.S. Non sto testando il codice che ti sto scrivendo, quindi pensaci due volte prima di fare copy&paste e prendere tutto per buono. Fai i dovuti test.
mah okay volevo chiederti anche un 'altra cosa riguardo un progetto sempre con grafo in cui devo gestire le prenotazioni di voli ho suddiviso l'accesso amministratore con utente come posso fare per metterli in collegamento cosi quando inserisco una città, ad esempio, se rinvio il programma la città inserita rimane ancora...puoi aiutarmi?
Diciamo che questo è il codice ora tutte le funzioni vanno ma come faccio a far comunicare amministratore e utente?
C:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "Graph.h"
#include "List.h"
#include "Menu.h"
#include <string.h>
#define MAXCITTA 7
#define MAXEMAILAMMINISTRATORE  20
#define MAXEMAILPWDADMINISTRATOR 7
#define MAXDELETECITTA 7
#define MAXTRATTE 40
#define MAXDELETETRATTE 40
#define MAXEMAIL 20
#define MAXPWD 7
#define MAXCITTAPARTENZA 30

int main() {
    int sceltaUt2;
    int sceltaUt1;
    int scelta;
    int sceltaUt;
    int sceltaAmministratore;
    char cittaPartenza[MAXCITTAPARTENZA];
    char email[MAXEMAIL];
    char pwd[MAXPWD];
    char deleteCity[MAXDELETECITTA];
    char city[MAXCITTA];
    char emailAdministrator[MAXEMAILAMMINISTRATORE];
    char pwdAdministrator[MAXEMAILPWDADMINISTRATOR];
    Graph g = NULL;
  //inizializzo matrice con città
 char** nomiCitta = (char**) calloc(20, sizeof(char*));
  for(int i=0; i<20; i++) nomiCitta[i] = (char*) calloc(256, sizeof(char));
  strcpy(nomiCitta[0],  "Napoli");
  strcpy(nomiCitta[1],  "Roma");
  strcpy(nomiCitta[2],  "Milano");
  strcpy(nomiCitta[3],  "Torino");
  strcpy(nomiCitta[4],  "Salerno");
  strcpy(nomiCitta[5],  "Praga");
  strcpy(nomiCitta[6],  "Bari");
  strcpy(nomiCitta[7],  "Londra");
  strcpy(nomiCitta[8],  "Cagliari");
  strcpy(nomiCitta[9],  "Venezia");
  strcpy(nomiCitta[10], "Calabria");
  strcpy(nomiCitta[11], "Firenze");
  strcpy(nomiCitta[12], "Palermo");
  strcpy(nomiCitta[13], "Catania");
  strcpy(nomiCitta[14], "Parma");
  strcpy(nomiCitta[15], "Verona");
  strcpy(nomiCitta[16], "Bergamo");
  strcpy(nomiCitta[17], "Bolzano");
  strcpy(nomiCitta[18], "Perugia");
  strcpy(nomiCitta[19], "Taranto");

                g = initGraph(20,nomiCitta); //popolo grafo
    addEdge(g, getCityIndexByName(g, "Milano"), getCityIndexByName(g, "Roma"), 30, 4.78);
    addEdge(g, getCityIndexByName(g, "Napoli"), getCityIndexByName(g, "Milano"),2 ,7.1);
    addEdge(g, getCityIndexByName(g, "Roma"), getCityIndexByName(g, "Milano"),3, 15.3);
    addEdge(g, getCityIndexByName(g, "Torino"), getCityIndexByName(g, "Salerno"), 4 , 17.1);
    addEdge(g, getCityIndexByName(g, "Verona"), getCityIndexByName(g, "Praga"), 4 , 40.5);
    addEdge(g, getCityIndexByName(g, "Praga"), getCityIndexByName(g, "Salerno"), 5, 38.2);
    addEdge(g, getCityIndexByName(g, "Salerno"), getCityIndexByName(g, "Praga"), 7, 21.3);
    addEdge(g, getCityIndexByName(g, "Firenze"), getCityIndexByName(g, "Londra"), 9, 10.1);
    addEdge(g, getCityIndexByName(g, "Bari"), getCityIndexByName(g,  "Perugia"), 10, 42.2);
    addEdge(g, getCityIndexByName(g, "Venezia"), getCityIndexByName(g, "Verona"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Calabria"), getCityIndexByName(g, "Bergamo"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Cagliari"), getCityIndexByName(g, "Verona"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Palermo"), getCityIndexByName(g, "Milano"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Catania"), getCityIndexByName(g, "Palermo"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Parma"), getCityIndexByName(g, "Verona"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Londra"), getCityIndexByName(g, "Bolzano"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Bergamo"), getCityIndexByName(g, "Perugia"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Bolzano"), getCityIndexByName(g, "Taranto"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Perugia"), getCityIndexByName(g, "Parma"),4, 46.4);
    addEdge(g, getCityIndexByName(g, "Taranto"), getCityIndexByName(g, "Milano"),4, 46.4);

    while((scelta = menu())){
    switch (scelta)
    {
    
     case 1:
                 printf("Insert e-mail: ");
                 scanf("%s", emailAdministrator);
                      
                 printf("Insert password (max 7 characters): ");
                 scanf("%s", pwdAdministrator);
              
            
              while((sceltaAmministratore = menuAmministratore())){
                 switch (sceltaAmministratore) {
                     case 1://stampa archivo con città
                
                            printGraph(g);
                      
                            break;
                        
                     case 2://inserisci città
                    
                         printf("Insert the city you want to enter:");
                         scanf("%s", city);
                        
                         addNode(g,city);
                        
                         printf("~Operation successfully performed~");

                          break;
                    
                     case 3://cancella città
                          
                           printf("Insert the city to be deleted:\n");
                           scanf("%s", deleteCity);
                          
                          removeNodeByString(g,deleteCity);

                         printf("~\nOperation successfully performed~\n");
                          
                         break;
                    case 4: /*Se l'amministatore  vuole uscire*/

                           printf("Thank you goodbye!\n");

                           return 0;

                            break;

                         default: /*Se l'utente sbaglia ad inserire il numero*/
                         printf("This button does not allow you to make choices! Try again!\n");

                            break;
                  }
              }
          
            return 0;
        
      break;

    case 2:
            while((sceltaUt = menuUtente())){
                switch (sceltaUt) {
        case 1:
                      
                printf("Inserisci l'email: ");
                scanf ("%s", email);
                      
                printf("Inserisci password(max 7 caratteri): ");
                scanf("%s", pwd);
                      
                printf("\niscrizione effettuata con successo\n");

                      break;
         case 2:
                        
                printf("Inserisci l'email: ");
                scanf ("%s", email);
            
                printf("Inserisci password(max 7 caratteri): ");
                scanf("%s", pwd);
            
                printf("\naccesso effettuata con successo\n");
            
                    while((sceltaUt1 = menuUtente1())){
                       switch (sceltaUt1) {
             case 1://visualizza prenotazioni attive
                                
                            break;
                                          
            case 2://effettua prenotazione
                                        
                    while((sceltaUt2 = menuUtente2())){
                            switch (sceltaUt2) {
                    case 1://visualizza tratta più breve
                                                                                
                                break;
                    case 2://visualizza meta più economica
                                                                            
                                break;
                    
                    case 3://visualizza meta più economica
                                                                    
                                break;
                    case 4://visualizza meta più gettonata
                        
                        printf("\nEnter city of start: ");
                        scanf("%s", cittaPartenza);
                        
                        srand( (unsigned int) time(NULL) );
                        
                        printf("\n The most popular destination is the following: ");
                        printf("%s\n", nomiCitta[rand()%9]);
                        
                          break;
                    
                case 5: /*Se l'amministatore  vuole uscire*/

                            printf("Thank you goodbye!\n");

                        return 0;

                    break;

        default: /*Se l'utente sbaglia ad inserire il numero*/
            printf("This button does not allow you to make choices! Try again!\n");
                   break;
                       }
                }
                                            
        return 0;
             break;
        }
      }
   }
}
                                                  
case 3: /*Se l'utente vuole uscire*/

      printf("Thank you for choosing the flight booking management service, come back to visit us!\n");

      return 0;

       break;

    default: /*Se l'utente sbaglia ad inserire il numero*/
    printf("This button does not allow you to make choices! Try again!\n");

       break;

          } /*Fine switch*/
    } /*Fine do*/
  return 0;
} /*Fine main*/
 
Non ho capito precisamente cosa hai fatto, cosa vorresti fare e qual'è il problema; ma se vuoi semplicemente fare un meccanismo di save&load ti basta fissare un formato semplice da parsare e rispettarlo alla lettera. Un possibile formato potrebbe essere:
Codice:
nodes_count
edges_count
name_1
name_2
name_3
...
name_n
source_1 target_1
source_2 target_2
... ...
source_n target_n
dove i primi due valori servono principalmente per semplificarti la vita nelle malloc e nei for. Un esempio di un grafo espresso in questo formato potrebbe essere:
Codice:
4
6
Milano
Tokyo
Manhattan
Londra
0 1
0 2
1 3
2 3
3 0
2 0
se ti è difficile gestire gli spazi usa la newline come separatore tra source e target: diventa meno human-readable, ma molto molto facile da parsare.
 
Ultima modifica:
Non ho capito precisamente cosa hai fatto, cosa vorresti fare e qual'è il problema; ma se vuoi semplicemente fare un meccanismo di save&load ti basta fissare un formato semplice da parsare e rispettarlo alla lettera. Un possibile formato potrebbe essere:
Codice:
nodes_count
edges_count
name_1
name_2
name_3
...
name_n
source_1 target_1
source_2 target_2
... ...
source_n target_n
dove i primi due valori servono principalmente per semplificarti la vita nelle malloc e nei for. Un esempio di un grafo espresso in questo formato potrebbe essere:
Codice:
4
6
Milano
Tokyo
Manhattan
Londra
0 1
0 2
1 3
2 3
3 0
2 0
se ti è difficile gestire gli spazi usa la newline come separatore tra source e target: diventa meno human-readable, ma molto molto facile da parsare.
Non ho capito scusa....in pratica ho L’amministratore e l’utente ora l’amministratore può inserire ed eliminare città ma poi dopo questo operazioni esco dal programma Ed è come se l’inserimento e la cancellazione non venissero effettuate e quindi l’utente non le vede
Messaggio unito automaticamente:

Non ho capito precisamente cosa hai fatto, cosa vorresti fare e qual'è il problema; ma se vuoi semplicemente fare un meccanismo di save&load ti basta fissare un formato semplice da parsare e rispettarlo alla lettera. Un possibile formato potrebbe essere:
Codice:
nodes_count
edges_count
name_1
name_2
name_3
...
name_n
source_1 target_1
source_2 target_2
... ...
source_n target_n
dove i primi due valori servono principalmente per semplificarti la vita nelle malloc e nei for. Un esempio di un grafo espresso in questo formato potrebbe essere:
Codice:
4
6
Milano
Tokyo
Manhattan
Londra
0 1
0 2
1 3
2 3
3 0
2 0
se ti è difficile gestire gli spazi usa la newline come separatore tra source e target: diventa meno human-readable, ma molto molto facile da parsare.
Non ho capito scusa....in pratica ho L’amministratore e l’utente ora l’amministratore può inserire ed eliminare città ma poi dopo questo operazioni esco dal programma Ed è come se l’inserimento e la cancellazione non venissero effettuate e quindi l’utente non le vede
Messaggio unito automaticamente:

Non ho capito scusa....in pratica ho L’amministratore e l’utente ora l’amministratore può inserire ed eliminare città ma poi dopo questo operazioni esco dal programma Ed è come se l’inserimento e la cancellazione non venissero effettuate e quindi l’utente non le vede
Messaggio unito automaticamente:


Non ho capito scusa....in pratica ho L’amministratore e l’utente ora l’amministratore può inserire ed eliminare città ma poi dopo questo operazioni esco dal programma Ed è come se l’inserimento e la cancellazione non venissero effettuate e quindi l’utente non le vede
Dovrei creare una funzione di logout
 
Non ho capito scusa....in pratica ho L’amministratore e l’utente ora l’amministratore può inserire ed eliminare città ma poi dopo questo operazioni esco dal programma Ed è come se l’inserimento e la cancellazione non venissero effettuate e quindi l’utente non le vede
Dopo che l'amministratore termina di inserire le città gli chiedi se vuole salvare i cambiamenti. Nel momento in cui vuoi salvare i cambiamenti, scrivi il grafo su un file. Uno dei possibili formati per quel file te l'ho scritto sopra. Chiudi il programma. Riapri il programma e, nel momento in cui dici che sei un utente, carichi il grafo a partire dal file di testo precedentemente salvato dall'amministratore.

Dovrei creare una funzione di logout
Questa è un'altra alternativa... anche più facile da implementare. Basta che non chiudi mai il programma.
 
Ultima modifica:
Dopo che l'amministratore termina di inserire le città gli chiedi se vuole salvare i cambiamenti. Nel momento in cui vuoi salvare i cambiamenti, scrivi il grafo su un file. Uno dei possibili formati per quel file te l'ho scritto sopra. Chiudi il programma. Riapri il programma e, nel momento in cui dici che sei un utente, carichi il grafo a partire dal file di testo precedentemente salvato dall'amministratore.


Questa è un'altra alternativa... anche più facile da implementare. Basta che non chiudi mai il programma.
potrei avere maggiori informazioni sulla seconda scelta...mi farebbe un gran piacere ho un progetto da consegnare domani ed ora ho scoperto questo problema..
Messaggio unito automaticamente:

potrei avere maggiori informazioni sulla seconda scelta...mi farebbe un gran piacere ho un progetto da consegnare domani ed ora ho scoperto questo problema..
dopo il menu dell'amministratore potrei scrivere questo che dovrebbe farmi tornare al menu generale prima dei quello dell'amministratore ma non lo fa posto il codice:
Codice:
printf("\nSi desidera tornare al Menu' Principale?");
                  printf("\n[y] Si, desidero tornare al Menu' Principale");
                  printf("\n[n] No, desidero uscire ");
                  printf("\nEffettua la tua scelta: ");
                  scanf("%s", &torna);
 
Il problema non è di certo in quel pezzetto di codice che hai scritto.

C:
#include <stdio.h>
#include <stdbool.h>

enum login {
  EXIT,
  ADMIN,
  USER
};

int login() {
  printf("chi sei?\n");
  printf("%d) admin\n", ADMIN);
  printf("%d) user\n", USER);
  printf("0) exit\n", USER);

  int choice = -1;
  while (0 > choice || choice > 2) {
    printf(">>> ");
    scanf("%d", &choice);
  }

  return choice;
}

void menu_admin() {
  bool logout = false;

  while (!logout) {
    printf("ciao admin, cosa vuoi fare?\n");
    printf("0) logout\n");
    printf("1) stampa pippo\n");

    int choice;
    printf(">>> ");
    scanf("%d", &choice);

    if (choice == 0) {
      printf("Goodbye!\n");
      logout = true;
    }
    else if (choice == 1) {
      printf("pippo\n");
    }
  }
}

void menu_user() {
  bool logout = false;

  while (!logout) {
    printf("ciao user, cosa vuoi fare?\n");
    printf("0) logout\n");
    printf("1) stampa pluto\n");

    int choice;
    printf(">>> ");
    scanf("%d", &choice);

    if (choice == 0) {
      printf("Goodbye!\n");
      logout = true;
    }
    else if (choice == 1) {
      printf("pluto\n");
    }
  }
}

int main() {
  enum login usertype;

  do {
    usertype = login();
    if (usertype == ADMIN) menu_admin();
    else if (usertype == USER) menu_user();
  } while (usertype != EXIT);

  return 0;
}

You get the point. Prova ad adattarlo al tuo codice.
 
Ultima modifica:
Il problema non è di certo in quel pezzetto di codice che hai scritto.

C:
#include <stdio.h>
#include <stdbool.h>

enum login {
  EXIT,
  ADMIN,
  USER
};

int login() {
  printf("chi sei?\n");
  printf("%d) admin\n", ADMIN);
  printf("%d) user\n", USER);
  printf("0) exit\n", USER);

  int choice = -1;
  while (0 > choice || choice > 2) {
    printf(">>> ");
    scanf("%d", &choice);
  }

  return choice;
}

void menu_admin() {
  bool logout = false;

  while (!logout) {
    printf("ciao admin, cosa vuoi fare?\n");
    printf("0) logout\n");
    printf("1) stampa pippo\n");

    int choice;
    printf(">>> ");
    scanf("%d", &choice);

    if (choice == 0) {
      printf("Goodbye!\n");
      logout = true;
    }
    else if (choice == 1) {
      printf("pippo\n");
    }
  }
}

void menu_user() {
  bool logout = false;

  while (!logout) {
    printf("ciao user, cosa vuoi fare?\n");
    printf("0) logout\n");
    printf("1) stampa pluto\n");

    int choice;
    printf(">>> ");
    scanf("%d", &choice);

    if (choice == 0) {
      printf("Goodbye!\n");
      logout = true;
    }
    else if (choice == 1) {
      printf("pluto\n");
    }
  }
}

int main() {
  enum login usertype;

  do {
    usertype = login();
    if (usertype == ADMIN) menu_admin();
    else if (usertype == USER) menu_user();
  } while (usertype != EXIT);

  return 0;
}

You get the point. Prova ad adattarlo al tuo codice.
Ok domani provo grazie mille
Messaggio unito automaticamente:

Il problema non è di certo in quel pezzetto di codice che hai scritto.

C:
#include <stdio.h>
#include <stdbool.h>

enum login {
  EXIT,
  ADMIN,
  USER
};

int login() {
  printf("chi sei?\n");
  printf("%d) admin\n", ADMIN);
  printf("%d) user\n", USER);
  printf("0) exit\n", USER);

  int choice = -1;
  while (0 > choice || choice > 2) {
    printf(">>> ");
    scanf("%d", &choice);
  }

  return choice;
}

void menu_admin() {
  bool logout = false;

  while (!logout) {
    printf("ciao admin, cosa vuoi fare?\n");
    printf("0) logout\n");
    printf("1) stampa pippo\n");

    int choice;
    printf(">>> ");
    scanf("%d", &choice);

    if (choice == 0) {
      printf("Goodbye!\n");
      logout = true;
    }
    else if (choice == 1) {
      printf("pippo\n");
    }
  }
}

void menu_user() {
  bool logout = false;

  while (!logout) {
    printf("ciao user, cosa vuoi fare?\n");
    printf("0) logout\n");
    printf("1) stampa pluto\n");

    int choice;
    printf(">>> ");
    scanf("%d", &choice);

    if (choice == 0) {
      printf("Goodbye!\n");
      logout = true;
    }
    else if (choice == 1) {
      printf("pluto\n");
    }
  }
}

int main() {
  enum login usertype;

  do {
    usertype = login();
    if (usertype == ADMIN) menu_admin();
    else if (usertype == USER) menu_user();
  } while (usertype != EXIT);

  return 0;
}

You get the point. Prova ad adattarlo al tuo codice.
Buongiorno ma cosi devo cambiare l'intero menu creato se voglio aggiungere solo la funzione di login come posso fare?
Messaggio unito automaticamente:

Senza fare assunzioni sul grafo, puoi fare un for per iterare tutti i possibili valori da 0 a nodes_count (escluso). A questo punto però dovresti cambiare DFS in questo modo:
C:
void DFS(struct TGraph* graph, int vertex) {
  if (graph->visited[vertex]) return; // already visited, do nothing

  struct TList* adjList = graph->adjLists[vertex];
  struct TList* temp = adjList;
  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  while (temp != NULL) {
    int connectedVertex = temp->vertex;

    if (graph->visited[connectedVertex] != 0) // cycle detected
        printf("The edge %d -> %d form a cycle\n", vertex, connectedVertex);

    temp = temp->next;
  }
}
Se il grafo è fortemente connesso (strongly connected) puoi risparmiarti il for e mettere un valore qualunque (diciamo 0). In ogni caso l'efficienza dell'algoritmo non cambia (O(V+E)) e continui a visitare ogni nodo una sola volta.

P.S. Non sto testando il codice che ti sto scrivendo, quindi pensaci due volte prima di fare copy&paste e prendere tutto per buono. Fai i dovuti test.
quindi fare tipo cosi utilizzando il ciclo:
printGraph(G);
for(int i=0; i<n; i++) {
DFS(G, n);
}
 
Premesso che l'unica cosa che ho letto è la tua implementazione dell'algoritmo DFS, io direi che basta fare questo:
C:
void DFS(struct TGraph* graph, int vertex) {
  struct TList* adjList = graph->adjLists[vertex];
  struct TList* temp = adjList;

  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  while (temp != NULL) {
    int connectedVertex = temp->vertex;

    if (graph->visited[connectedVertex] == 0) {
      DFS(graph, connectedVertex);
    } else {
        printf("The edge %d -> %d form a cycle\n", vertex, connectedVertex); // unica riga che ho aggiunto
    }
    temp = temp->next;
  }
}
Prova a fare qualche test per vedere se ti quaglia tutto, poi prova a eliminare il ciclo rimuovendo l'elemento incriminato (connectedVertex) dalla lista di adiacenza del nodo attualmente visitato (temp).
Ho provato ma non mi funziona mi viene stampato questo
1591279354732.png

Messaggio unito automaticamente:

Ho provato ma non mi funziona mi viene stampato questo
1591279354732.png
mi puo aiutare?
 
Ho provato ma non mi funziona mi viene stampato questo
Visualizza allegato 43466
Messaggio unito automaticamente:


mi puo aiutare?

C:
Graph initGraph(int nodes_count) {
    Graph G = (Graph)malloc(sizeof(struct TGraph));
    G->adj = (List *)calloc(nodes_count, sizeof(List));
    G->nodes_count = nodes_count;
    G->visited = (int *)calloc(nodes_count, sizeof(int));
    return G;
}

void DFS(struct TGraph* graph, int vertex) {
  if (graph->visited[vertex]) return;

  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  for (struct TList* p = graph->adj[vertex]; p != NULL; p = p->next) {
    int connectedVertex = p->target;

    if (graph->visited[connectedVertex] != 0)
        printf("The edge %d -> %d form a cycle\n", vertex, connectedVertex);

    DFS(graph, connectedVertex);
  }
}
nel main:
C:
printf("Starting DFS for cycle detection\n");
for (int i = 0; i < G->nodes_count; i++) {
    DFS(G, i);
    for (int i = 0; i < G->nodes_count; i++) G->visited[i] = 0;
}

Il tuo codice ha più di un problema, tipo quel adjList in TGraph che non serve a niente e diverse altre cose. Si vede che l'hai un po' fatto scopiazzando qua e là dai forum. Io mi sono limitato a fare lo stretto indispensabile per far funzionare quello che hai chiesto, ma se fossi in te me lo rivedrei dall'inizio e gli darei una bella ripulita.

Devi cercare di essere un po' più autonoma ;)
 
  • Mi piace
Reazioni: sara20
Ultima modifica:
C:
Graph initGraph(int nodes_count) {
    Graph G = (Graph)malloc(sizeof(struct TGraph));
    G->adj = (List *)calloc(nodes_count, sizeof(List));
    G->nodes_count = nodes_count;
    G->visited = (int *)calloc(nodes_count, sizeof(int));
    return G;
}

void DFS(struct TGraph* graph, int vertex) {
  if (graph->visited[vertex]) return;

  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  for (struct TList* p = graph->adj[vertex]; p != NULL; p = p->next) {
    int connectedVertex = p->target;

    if (graph->visited[connectedVertex] != 0)
        printf("The edge %d -> %d form a cycle\n", vertex, connectedVertex);

    DFS(graph, connectedVertex);
  }
}
nel main:
C:
printf("Starting DFS for cycle detection\n");
for (int i = 0; i < G->nodes_count; i++) {
    DFS(G, i);
    for (int i = 0; i < G->nodes_count; i++) G->visited[i] = 0;
}

Il tuo codice ha più di un problema, tipo quel adjList in TGraph che non serve a niente e diverse altre cose. Si vede che l'hai un po' fatto scopiazzando qua e là dai forum. Io mi sono limitato a fare lo stretto indispensabile per far funzionare quello che hai chiesto, ma se fossi in te me lo rivedrei dall'inizio e gli darei una bella ripulita.

Devi cercare di essere un po' più autonoma ;)
va bene proverò ma ora per eliminare il ciclo posso usare una delle funzioni che già ho tipo removeNode? quindi ho removeNode(G,i)??
Ho anche un'altro problema che si rifà ad un progetto di cui ti ho già parlato qualche giorno fa ed ho fatto come mi avevi detto fa collegare utente ed amministratore ora in pratica io ho che nel utente prima di fare una prenotazione deve effettuare l'iscrizione oppure l'accesso se è già iscritto ho fatto cosi:ma
1)il menuUtente1 si ripete all'infinito cioè metto 1 e poi mi esce di nuovo il menù
2)l'iscrizione la faccio con una lista e poi la inserisco in coda ma come faccio a far si che poi la stessa iscrizione sia utilizzata per l'accesso?
Codice:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include "Graph.h"
#include "List.h"
#include "Queue.h"
#include "Menu.h"
#include "ListPrenotazioni.h"
#include "ListUtente.h"



#define BUFFER_SIZE 256
#define randomize srand(time(NULL))
#define random(x) rand()%x

int main(int argc, char** argv){
    int n=0;
    char email[100];
    char pwd[7];
    Lista L;
    ListUtente l=NULL;//per listUtente
    randomize;
    Graph g = populateGraph();
    //int mostPopularDestination = random(g->nodes_count);
    char buffer_email[BUFFER_SIZE];
    char buffer_password[BUFFER_SIZE];
    // qui va inserita la DS per contenere gli utenti registrati, e la DS per contenere i voli prenotati da un utente
    int loginChoice;
    int adminChoice;
    int userChoice;
    int user1Choice;
    bool continueLoop;
    do{
        loginChoice = displayLoginMenu();
        if(loginChoice == 0){  //azioni amministratore
            continueLoop = true;
           
            printf("Insert e-mail: ");
            scanf("%s", buffer_email);
                   
            printf("Insert password (max 7 characters): ");
            scanf("%s", buffer_password);
           
            /*
            Se l'admin non e' presente nella data structure degli admin --> continueLoop = false
                In questo modo torna al menu di login e non vengono eseguite operazioni
            */
            while(continueLoop){
                adminChoice = displayAdminMenu();
                switch (adminChoice){
                case 0: // exit / logout
                    printf("admin logout\n");
                    continueLoop = false;
                    break;
                case 1: // stampa destinazioni
                    printGraph(g);
                    break;
                case 2: // inserisci destinazioni
                    addNode(g, getCityName("new destination"));
                   
                     printf("~Operation successfully performed~");
                    break;
                case 3: // cancella destinazioni
                    removeNodeByIndex(g, getCityIndex(g, "target city"));
                   
                        printf("~Operation successfully performed~");
                     //mostPopularDestination = random(g->nodes_count);-->utente nella scelta meta più gettonata
                    break;
                   
                }
            }
        }else if(loginChoice == 1){//azioni utenti
            continueLoop = true;
               while (continueLoop){
                               user1Choice = displayUserMenu1();
                               switch (user1Choice){
                                  case 0: // exit/logout
                                    printf("user logout\n");
                                    continueLoop = false;
                             
                                  case 1://effettuo iscrizione
                                   
                                     for(int i=0; i<n; i++){
                                         printf("Inserire email %d\n",i);
                                         scanf("%s",email);
                                         printf("Inserire password %d\n",i);
                                         scanf("%s",pwd);
                                         l=insertTail(l,email,pwd);
                                     }
                                     break;
                                     
                                 case 2:
                                     
                                     
                                   
                                break;
                                     
               }
        }
            /*
            Se l'user non e' presente nella data structure degli user --> chiediamo se si vuole iscrivere
                 oppure puo' uscire e tornare al menu di login
            */
            while (continueLoop){
                userChoice = displayUserMenu();
                switch (userChoice){
                case 0: // exit/logout
                    printf("user logout\n");
                    continueLoop = false;
                    break;
                case 1: // effettua prenotazione
                        L = InserimentoPrenotazione();
                        printf("\n");
                        stampaElenco(L);
                    // in base al tipo di scelta occorre aggiungere un nodo alla Data Structure delle prenotazioni
                        break;
                 case 2: // vedi prenotazioni
                     // stampaElenco(L);

                    break;
               
                }
            }
        }
   
       else if(loginChoice == 2){
            printf("Thank you for choosing the flight booking management service, come back to visit us!\n");
       }else{
            printf("This button does not allow you to make choices! Try again!\n");
         }
    }while(loginChoice != 2);
    return 0;
}
grazie in anticipo
 
va bene lo leggerò
Codice:
1)il menuUtente1 si ripete all'infinito

Non esiste nel codice qualcosa che si chiami menuUtente1
si c'è eccolo
Codice:
int displayUserMenu1(){
    printf("                   **************** \n");
    printf("                         USER          \n");
    printf("                   ****************     \n");
    
    printf(" 0. logOut\n");
    printf(" 1. SignUp\n");
    printf(" 2. SignIn\n");
    int choice = -1;
    while (choice < 0 || choice > 2) {
        printf("Insert choice thanks: ");
        scanf("%d", &choice);
        
    }
    return choice;
}
 
Ultima modifica:
menuUtente1 (non esiste) è una cosa, displayUserMenu1 è un'altra ... usa i nomi di funzione corretti, dato che l'hai scelti tu, dovresti indicarli correttamente.

Comunque, la funzione displayUserMenu1 lavora correttamente. SE tu la chiami all'interno di un ciclo, naturalmente sarà chiamata nuovamente finché il ciclo non termina.
 
menuUtente1 (non esiste) è una cosa, displayUserMenu1 è un'altra ... usa i nomi di funzione corretti, dato che l'hai scelti tu, dovresti indicarli correttamente.

Comunque, la funzione displayUserMenu1 lavora correttamente. SE tu la chiami all'interno di un ciclo, naturalmente sarà chiamata nuovamente finché il ciclo non termina.
Scusa con menuUtente intendevo “displayUserMenu1” dove inserisco la scelta è poi ritorna lo stesso menu con la scelta
 
Ti vorrei dare una mano ma c'e' troppa confusione, fai uno zip con tutto il progetto e caricalo, altrimenti un pezzetto qua un pezzetto la non si capisce nulla, nel primo post c'e' una main dove non si parla di login ma di vertici, poi nella pagina dopo appare tutt'altro, in un altra ancora ci sono le citta'...
 
Stato
Discussione chiusa ad ulteriori risposte.