#include #include struct action { int id; GPtrArray *depends; GPtrArray *required_by; }; void free_action(gpointer data) { struct action *action = (struct action *)data; g_ptr_array_free(action->depends, TRUE); g_ptr_array_free(action->required_by, TRUE); g_free(action); } struct action *get_action(GHashTable *table, int id) { struct action *action = g_hash_table_lookup(table, GINT_TO_POINTER(id)); if (action) return action; action = g_malloc(sizeof(struct action)); action->depends = g_ptr_array_new(); action->required_by = g_ptr_array_new(); action->id = id; g_hash_table_insert(table, GINT_TO_POINTER(id), action); return action; } gint compare_action(gconstpointer _a, gconstpointer _b) { struct action *a = *(struct action **)_a; struct action *b = *(struct action **)_b; return a->id - b->id; } GHashTable *parse_tree(const char *fname) { FILE *f = fopen(fname, "r"); if (!f) { perror(fname); return NULL; } GHashTable *table = g_hash_table_new_full(NULL, NULL, NULL, free_action); char *line = NULL; size_t line_len = 0; while (getline(&line, &line_len, f) != -1) { char depends = 0; char required_by = 0; sscanf(line, "Step %c must be finished before step %c can begin.", &depends, &required_by); struct action *dependent = get_action(table, depends); struct action *required = get_action(table, required_by); g_ptr_array_add(dependent->required_by, required); g_ptr_array_add(required->depends, dependent); } free(line); fclose(f); return table; } int main() { GHashTable *table = parse_tree("input"); if (!table) return 1; GPtrArray *queue = g_ptr_array_new(); GString *result = g_string_new(NULL); // Find items without dependencies GHashTableIter iter; gpointer key, value; g_hash_table_iter_init(&iter, table); while (g_hash_table_iter_next(&iter, &key, &value)) { struct action *action = (struct action *)value; if (action->depends->len == 0) { g_ptr_array_add(queue, action); } } struct action *workers[5] = {0}; unsigned workers_time[5] = {0}; unsigned working = 0; unsigned time = 0; do { g_ptr_array_sort(queue, compare_action); while (queue->len && working < 5) { struct action *action = g_ptr_array_remove_index(queue, 0); workers[working] = action; workers_time[working++] = action->id - 'A' + 1 + 60; } for (unsigned i = 0; i < working; i++) { if (--workers_time[i] != 0) continue; struct action *action = workers[i]; memmove(workers + i, workers + i + 1, sizeof(struct action *) * (5 - i - 1)); memmove(workers_time + i, workers_time + i + 1, sizeof(unsigned) * (5 - i - 1)); working--; i--; g_string_append_c(result, action->id); for (unsigned i = 0; i < action->required_by->len; i++) { struct action *next = g_ptr_array_index(action->required_by, i); g_ptr_array_remove_fast(next->depends, action); if (next->depends->len == 0) g_ptr_array_add(queue, next); } } time++; } while (queue->len || working); puts(result->str); printf("%u\n", time); g_string_free(result, TRUE); g_ptr_array_free(queue, TRUE); g_hash_table_destroy(table); return 0; }