#include #include #include static void *xrealloc(void *ptr, size_t size) { ptr = realloc(ptr, size); if (!ptr) abort(); return ptr; } static void *xmalloc(size_t size) { void *ptr = malloc(size); if (!ptr) abort(); return ptr; } static void *xcalloc(size_t nmemb, size_t size) { void *ptr = calloc(nmemb, size); if (!ptr) abort(); return ptr; } /* Linked list of trie nodes. Each node represent one character, * has an index of vertex and contains linked list of neighbors */ struct trie_node { char ch; /* current character */ unsigned int vertex; /* index of vertex */ struct trie_node *down; /* pointer to linked list of edges from current character */ struct trie_node *next; /* next member of linked list, another node of upper character */ }; /* Allocate a new trie node */ static struct trie_node *trie_new_node(char ch) { struct trie_node *node; node = xmalloc(sizeof(*node)); node->ch = ch; node->vertex = 0; node->down = NULL; node->next = NULL; return node; } /* Insert a string into trie */ static int trie_insert(struct trie_node *root, const char *str, unsigned int *last_vertex) { struct trie_node *node = root; size_t len = strlen(str); size_t i; for (i = 0; i < len; ++i) { /* Check if node with linked list of characters exists, if not create it */ if (!node->down) node->down = trie_new_node(str[i]); node = node->down; /* Find node with current character in linked list */ while (node->ch != str[i] && node->next) node = node->next; /* If it does not exist yet, create one and append to the end */ if (node->ch != str[i]) { node->next = trie_new_node(str[i]); node = node->next; } } if (!node->vertex) node->vertex = ++(*last_vertex); return node->vertex; } /* Vertex index and pointer to the next member of linked list */ struct graph_node { int vertex; struct graph_node *next; }; /* One graph vertex, contains linked list of neighbors */ struct graph_vertex { char *str; struct graph_node *node; }; /* Depth first search starting from the vertex index of the graph, update visited */ static unsigned int graph_dfs(struct graph_vertex *graph, int vertex, char *visited) { struct graph_node *node; unsigned int count; /* Do not process this vertex if we have already visited it */ if (visited[vertex]) return 0; visited[vertex] = 1; count = 1; /* Iterate over all neighbor vertices */ for (node = graph[vertex].node; node; node = node->next) count += graph_dfs(graph, node->vertex, visited); return count; } /* Scan next line from the standard input, trim trailing newline */ static void scan_line(char *buffer, size_t len) { if (!fgets(buffer, len, stdin)) abort(); len = strlen(buffer); if (len < 2) abort(); buffer[len-1] = 0; } int main() { unsigned int last_vertex, vertex1, vertex2; struct trie_node *trie_name; struct trie_node *trie_email; struct graph_vertex *graph; struct graph_node *graph_node; unsigned int n, i, count, graph_nodes; char *visited; char line[256]; last_vertex = 0; trie_name = trie_new_node(0); trie_email = trie_new_node(0); /* Graph is array of vertices, preallocate memory for 64 members */ graph_nodes = 64; graph = xcalloc(graph_nodes, sizeof(*graph)); /* First line of the input must contain number of records */ if (scanf("%u\n", &n) != 1) abort(); for (i = 0; i < n; ++i) { /* Then each pair of two lines contains email and name of one person */ scan_line(line, sizeof(line)); vertex1 = trie_insert(trie_email, line, &last_vertex); scan_line(line, sizeof(line)); vertex2 = trie_insert(trie_name, line, &last_vertex); /* Reallocate memory if graph array is too small */ if (vertex1 >= graph_nodes || vertex2 >= graph_nodes) { graph = xrealloc(graph, sizeof(*graph) * graph_nodes * 2); memset(graph + graph_nodes, 0, sizeof(*graph) * graph_nodes); graph_nodes *= 2; } /* Allocate memory for edge vertex1 --> vertex2 */ graph_node = xmalloc(sizeof(*graph_node)); graph_node->vertex = vertex2; graph_node->next = graph[vertex1].node; graph[vertex1].node = graph_node; if (!graph[vertex1].str) graph[vertex1].str = strdup(line); /* Allocate memory for edge vertex2 --> vertex1 */ graph_node = xmalloc(sizeof(*graph_node)); graph_node->vertex = vertex1; graph_node->next = graph[vertex2].node; graph[vertex2].node = graph_node; if (!graph[vertex2].str) graph[vertex2].str = strdup(line); } /* Initialize array visited, set to to zeros */ visited = xcalloc(last_vertex+1, 1); /* Iterate over all vertices */ for (i = 1; i <= last_vertex; ++i) { /* Run DFS from current vertex and if number of visited vertices is non-zero, then we found a new person */ count = graph_dfs(graph, i, visited); if (count > 0) printf("Person with name `%s' has %u record(s)\n", graph[i].str, count); } return 0; }