From 6b5954d0e5f536971acc0e3a69b0f75d2c1f9d2b Mon Sep 17 00:00:00 2001 From: Manuel Bucher <manuel.bucher@hu-berlin.de> Date: Fri, 22 Jun 2018 17:54:19 +0200 Subject: [PATCH] overwrite loesung with loesung2 --- Makefile | 6 +- loesung.c | 599 +++++++++++++++++++++-------------------------------- loesung2.c | 378 --------------------------------- 3 files changed, 236 insertions(+), 747 deletions(-) mode change 100644 => 100755 loesung.c delete mode 100755 loesung2.c diff --git a/Makefile b/Makefile index ebb9bf3..742516b 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ -all: loesung2 +all: loesung WARNINGS = -Wall #-Werror OPTIONAL = -Wextra -Wpedantic -Wshadow DEBUG = -g -ggdb -fno-omit-frame-pointer OPTIMIZE = -Og -std=c11 -loesung: Makefile loesung2.c - $(CC) -o $@ $(WARNINGS) $(OPTIONAL) $(DEBUG) $(OPTIMIZE) loesung2.c +loesung: Makefile loesung.c + $(CC) -o $@ $(WARNINGS) $(OPTIONAL) $(DEBUG) $(OPTIMIZE) loesung.c clean: rm -f loesung diff --git a/loesung.c b/loesung.c old mode 100644 new mode 100755 index 0f10c42..5b37b0b --- a/loesung.c +++ b/loesung.c @@ -1,203 +1,91 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <stdint.h> // fixed sized integer #include <stdbool.h> // booleans #define INF UINT32_MAX +/********** Kachel definition **********/ typedef struct Tile { uint32_t x; uint32_t y; - struct Tile *p_matching; // matching partner - struct Tile *p_next; // used for list and queue - struct Tile *p_n; // north has to be first - struct Tile *p_e; // east - struct Tile *p_s; // south - struct Tile *p_w; // west - uint32_t dist; + uint32_t neigh[4]; // Nachbarn + struct Tile *p_next; // queue + uint32_t pair; // matching partner + uint32_t dist; // entfernung zu Knoten 0 im Schichtgraph } Tile; - -// Reservieren und initialisieren des Speicherplatz eines Tiles -void tile_init(Tile* this) { - this->x = 0; - this->y = 0; - this->p_matching = NULL; - this->p_next = NULL; - this->p_n = NULL; - this->p_e = NULL; - this->p_s = NULL; - this->p_w = NULL; +// initialisieren des Speichers von einem Tile +void tile_init(Tile *this) { + memset(this, 0, sizeof(Tile)); this->dist = INF; } int tile_compare(const void *p, const void *q) { - const Tile *s = *(const Tile**) p; - const Tile *t = *(const Tile**) q; - // als erstes nach y sortieren - if (s->y < t->y) - return -1; - if (s->y > t->y) - return 1; - // danach nach x sortieren - if (s->x < t->x) - return -1; - if (s->x > t->x) - return 1; + const Tile *s = (const Tile*) p; + const Tile *t = (const Tile*) q; + // als erstes nach x sortieren + if (s->x < t->x) return -1; + if (s->x > t->x) return 1; + // danach nach y sortieren + if (s->y < t->y) return -1; + if (s->y > t->y) return 1; return 0; // Elemente sind gleich } -inline bool tile_is_odd(Tile* this) { - return ((this->x ^ this->y)&1) != 0; +// Kacheln wie im Schachbrettmuster einordnen +uint32_t tile_odd(Tile* this) { + return ((this->x ^ this->y)&1); } -/*************** List von Tiles *********************/ -/** List von Tiles */ -typedef struct List { - Tile *p_top; +/********** Kachelfeld **********/ +typedef struct Field { + // Array von Tiles, tile 0 is imagenary tile for hk-algorithmus + // Tiles werden mit 1 bis num_tiles exklusive indiziert + Tile *tiles; uint32_t num_tiles; - uint32_t num_odd; // #ungerade Felder (`x - y` ist ungerade) - Tile max; - Tile min; -} List; - -/** Initialisieren einer leeren Liste */ -void list_init(List *this) { - this->p_top = NULL; - this->num_tiles = 0; - this->num_odd = 0; - this->min.x = UINT32_MAX; - this->min.y = UINT32_MAX; - this->max.x = 0; - this->max.y = 0; -} - -/** Min-Max funktionen fuer uint32_t */ -inline uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; } -inline uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; } - -/** Hinzufuegen von einem Tile zur Liste - * - * Voraussetzung: Die Liste muss initialisiert sein. - * Rueckgabe: Hinzugefuegtes, initialisiertes Tile - */ -void list_push(List *this, Tile *p_tile) { - p_tile->p_next = this->p_top; - this->p_top = p_tile; - // Reichweite der Liste ermitteln - this->min.x = min(this->min.x, p_tile->x); - this->min.y = min(this->min.y, p_tile->y); - this->max.x = max(this->max.x, p_tile->x); - this->max.y = max(this->max.y, p_tile->y); - this->num_tiles++; - this->num_odd += tile_is_odd(p_tile); + uint32_t size; + uint32_t num_odd; +} Field; + +// returns 0 if successful, nonzero if failed +int field_init(Field *this) { + memset(this, 0, sizeof(Field)); + this->tiles = malloc(sizeof(Tile)); + this->num_tiles = 1; + this->size = 1; + return this->tiles == 0; } -/** Freigeben des reservierten Speichers von der Liste - * - * Alle Tiles mit free vom Speicher freigeben - */ -void list_free(List *this) { - Tile *p_cur = this->p_top; - this->p_top = NULL; - while (p_cur != NULL) { - Tile *p_next = p_cur->p_next; - free(p_cur); - p_cur = p_next; - } -} - -/** pruefen, ob genausoviele gerade und ungerade Kacheln existieren, - * ohne einen Overflow zu erzeugen - * notwendiges Kriterium - */ -bool list_necessity(List *this) { - return this->num_tiles - this->num_odd == this->num_odd; -} - -/** Zurueckgeben, ob graph ein vollstaendiges Rechteck ist */ -bool list_rectangle(List *this) { - // verwenden von `uint64_t` um einen ueberlauf zu vermeiden - return (uint64_t)(this->max.x - this->min.x+1) * (uint64_t)(this->max.y - this->min.y+1) - == (uint64_t)this->num_tiles; -} - -/** Ausgeben der Liste als Rechteck - * - * Voraussetzung: notwendiges Kriterium erfuellt & es handelt sich um ein Rechteck - */ -void list_print_rectangle(List *this) { - for (uint32_t x = this->min.x;; x++) { - for (uint32_t y = this->min.y;; y+=2) { - if (y == this->max.y) { - if ((x - this->min.x) % 2 == 0) { - // vertikaler Stein - printf("%u %u;%u %u\n", x, y, x+1, y); - } - break; - } - printf("%u %u;%u %u\n", x, y, x, y+1); - if (y == this->max.y-1) { - break; // ende des Zeile erreicht - } - } - if(x == this->max.x) { - break; - } +// if an error occurs, all memory get freed +int field_push(Field *this, Tile *p_tile) { + if (this->size == this->num_tiles) { + if (this->size == 1u<<31) return 1; // catch overflow + this->size *= 2; // Armortisiert O(1) + Tile *new = realloc(this->tiles, this->size*sizeof(Tile)); + if (new == NULL) return 1; // catch failed realloc + this->tiles = new; } -} - -/** Schlange von Tiles */ -typedef struct Queue { - Tile *p_first; - Tile *p_last; -} Queue; - -void queue_init(Queue* this) { - this->p_first = NULL; - this->p_last = NULL; -} - -void queue_push(Queue* this, Tile* p_tile) { - if (this->p_last != NULL) { - this->p_last->p_next = p_tile; - } else { - this->p_first = p_tile; - } - this->p_last = p_tile; - p_tile->p_next = NULL; -} - -inline Tile *queue_first(Queue* this) { - return this->p_first; -} - -inline bool queue_empty(Queue* this) { - return this->p_first == NULL; -} - -Tile *queue_pop(Queue* this) { - Tile *p_tile = this->p_first; - this->p_first = p_tile->p_next; - if (this->p_first == NULL) { - this->p_last = NULL; - } - return p_tile; + this->num_odd += tile_odd(p_tile); + memcpy(this->tiles+this->num_tiles, p_tile, sizeof(Tile)); + this->num_tiles++; + return 0; } /** Parsen einer Kachel(Tile) aus einer Zeile von StdIn * - * Die Zahlen weReaden in das uebergebene Struct pTile geschrieben, sind aber - * nur gueltig, wenn der Rueckgabewert `Ok` ist. + * Die Werte werden in die uebergebene Kachel geschrieben, sind aber + * nur gueltig, wenn der Rueckgabewert `ReadOk` ist. * * Voraussetzung: p_tile muss initialisiert sein */ typedef enum ReadResult { ReadOk, ReadEof, - ReadErrIntegerOverflow, - ReadErrNonDigitCharacter, + ReadErrOverflow, + ReadErrInvalidChar, ReadErrTooFewNumbers, ReadErrTooManyNumbers, ReadErrOutOfMemory, @@ -223,18 +111,16 @@ ReadResult read_line(Tile* p_tile){ // 429496730 = 2^32 / 10, daher wenn `p_cur` groesser ist, wird ein // overflow erzeugt if (*p_cur > 429496729) { - return ReadErrIntegerOverflow; + return ReadErrOverflow; } (*p_cur) *= 10; int digit = c - '0'; if (*p_cur > UINT32_MAX - digit) { - return ReadErrIntegerOverflow; + return ReadErrOverflow; } (*p_cur) += digit; } else if (c == ' ') { - if (cur_whitespace == false) { - cur_whitespace = true; - } + cur_whitespace = true; } else if (c == '\n') { if (cur_number == 2) { return ReadOk; @@ -242,11 +128,10 @@ ReadResult read_line(Tile* p_tile){ return ReadErrTooFewNumbers; } } else { - return ReadErrNonDigitCharacter; + return ReadErrInvalidChar; } c = getchar(); // get next character } - return ReadOk; } /** Liest das Input von StdIn und schreibt das Ergebnis in die uebergebene Liste @@ -254,33 +139,26 @@ ReadResult read_line(Tile* p_tile){ * Laufzeit: O(n) * Speicherbedarf: O(n) * - * Parameter: - * - List* f ist ein Pointer auf eine initialisierte List, wird mit Eingabe - * gefuellt, im Fehlerfall ist die groesse `num_tiles` die Zeile, in welche - * der Fehler aufgetreten ist - * * Return: * - ReadResult: * ReadOk, falls das lesen Erfolgreich war - * ReadErr..., falls die Eingabe ungueltig ist. `f` ist dann nicht vollstaendig - * initialisiert + * ReadErr..., falls die Eingabe ungueltig ist oder zu wenig Speicher vorhanden. + * `num_tiles` indiziert die Zeile, in der der Fehler aufgetreten ist */ -ReadResult parse_input(List *this) { +ReadResult field_parse(Field *this) { while (1) { - Tile *p_tile = malloc(sizeof(Tile)); - if (p_tile == NULL) { - return ReadErrOutOfMemory; - } - tile_init(p_tile); - ReadResult result = read_line(p_tile); + Tile next; + tile_init(&next); + ReadResult result = read_line(&next); switch (result) { case ReadOk: // einfuegen in die Liste - list_push(this, p_tile); + if (field_push(this, &next)) { + return ReadErrOutOfMemory; + } break; case ReadEof: - free(p_tile); - if (this->num_tiles == 0) { + if (this->num_tiles == 1) { return ReadEof; } else { return ReadOk; @@ -291,221 +169,210 @@ ReadResult parse_input(List *this) { } } -/** Array in heap for accessing tiles in O(1) - */ -typedef struct Array { - uint32_t num_tiles; - Tile null; - Tile* (*tiles); -} Array; - -/** Freigeben des im Heap reservierten Speichers des tile_arrays f - * inklusive der Tiles */ -void array_drop(Array *this) { - if(this->tiles != NULL) { - for(uint32_t i = 1; i < this->num_tiles; i++) { - free(this->tiles[i]); - } - free(this->tiles); - } -} - -typedef enum MallocResult { - MallocFailed, - MallocOk, -} MallocResult; -/** Initialisieren des Tile-Arrays - * - * Laufzeit: O(n) - */ -MallocResult array_from_list(Array *this, List* p_list) { - this->num_tiles = p_list->num_tiles+1; - this->tiles = malloc(this->num_tiles * sizeof(Tile*)); - if(this->tiles == NULL) { - return MallocFailed; - } - tile_init(&this->null); // create null tile for hk - this->tiles[0] = &this->null; - Tile *cur = p_list->p_top; - for (uint32_t i = 1; i < this->num_tiles; i++) { - this->tiles[i] = cur; - cur = cur->p_next; - this->tiles[i]->p_next = NULL; - } - return MallocOk; -} - -/** Gruppieren der Felder, setzen der Pointer (north, east, south, west) vom Feld - * - * Voraussetzung: `field_init_tile_array()` muss ausgefuehrt worden sein +/** Setzen der Nachbarn der Kacheln * Rueckgabe: 0 falls alles ok - * 1 falls Dopplungen vorkommen TODO: enum + * 1 falls Dopplungen vorkommen */ -int array_find_neighbours(Array *this) { - uint32_t i = 1; // vergleich mit oberer Zeile - uint32_t begin_line = 1; - for (uint32_t j = 2; j < this->num_tiles; j++) { - Tile *p_cur = this->tiles[j]; - Tile *p_east = this->tiles[j-1]; - // ermitteln der ost/west-Beziehung - if (p_cur->y == p_east->y) { - if (p_cur->x == p_east->x) { - return 1; - } - if (p_cur->x == p_east->x - 1) { - p_cur->p_e = p_east; - p_east->p_w = p_cur; +int field_neighbours(Field *this) { + uint32_t top = 1; // vergleich mit oberer Zeile + uint32_t begin_line = 1; // start der aktuellen Zeile + Tile *t = this->tiles; + for (uint32_t cur = 2; cur < this->num_tiles; cur++) { + // ermitteln der x-Beziehung + uint32_t east = cur-1; + if (t[cur].x == t[east].x) { // gleiche Zeile + if (t[cur].y == t[east].y) { // gleiche Spalte + return 1; // Doppelung + } else if (t[cur].y-1 == t[east].y) { + t[cur].neigh[1] = east; + t[east].neigh[3] = cur; } } else { - begin_line = i; + top = begin_line; + begin_line = cur; // neue Zeile } - // ermitteln der nord/sued-Beziehung - Tile *p_north = this->tiles[i]; - if (p_north->y < p_cur->y - 1) { - i = begin_line; // Luecke zwischen zeilen - } else if (p_north->y == p_cur->y - 1) { - // finden, ob paar existiert, zurzeit O(n). - for(;this->tiles[i]->y < p_cur->y && i < begin_line; i++); - p_north = this->tiles[i]; - if (p_north->x == p_cur->x) { - p_north->p_s = p_cur; - p_cur->p_n = p_north; + // ermitteln der Zeilen-Beziehung + if (t[begin_line].x != 0 && t[top].x < t[begin_line].x - 1) { + // Zeilensprung => Warten bis zur naechsten Zeile angekommen + } else if (t[top].x == t[cur].x - 1) { + // finden, ob paar nach oben existiert O(n) fuer alle Nachbarn nach oben/unten. + for(;t[top].y < t[cur].y && top < begin_line; top++); + + // aktuelle obere Kachel koennte benachbart sein + if (t[top].y == t[cur].y) { // nicht auf naechste Zeile uebergegangen + // Neue Verbindung oben/unten gefunden + t[top].neigh[2] = cur; + t[cur].neigh[0] = top; } } } return 0; } -void array_print(Array *this) { - printf("# Array\n"); - for (uint32_t i = 0; i < this->num_tiles; i++) { - printf("%u %u\n", this->tiles[i]->x, this->tiles[i]->y); +void field_print(Field *this) { + printf("[\n"); + Tile *t = this->tiles; + for (uint32_t i = 1; i < this->num_tiles; i++){ + printf("\t(%u %u): {", t[i].x, this->tiles[i].y); + for (int j = 0; j < 4; j++) { + if(t[i].neigh[j] != 0) { + Tile *neigh = &t[t[i].neigh[j]]; + printf(" (%u %u)", neigh->x, neigh->y); + } + } + printf(" }\n"); + } + printf("]\n"); +} + +/********** Schlange von Tiles **********/ +typedef struct Queue { + Tile *p_first; + Tile *p_last; +} Queue; + +void queue_init(Queue* this) { + this->p_first = NULL; + this->p_last = NULL; +} + +void queue_push(Queue* this, Tile* p_tile) { + if (this->p_last != NULL) { + this->p_last->p_next = p_tile; + } else { + this->p_first = p_tile; } + this->p_last = p_tile; + p_tile->p_next = NULL; } -/* algorithmus von Hopcroft und Karp */ -bool hk_bfs(Array *this) { - Queue q; - queue_init(&q); // queue von odd Tiles +bool queue_empty(Queue* this) { + return this->p_first == NULL; +} - for (int i = 0; i < this->num_tiles; i++) { - Tile *p_cur = this->tiles[i]; - if (tile_is_odd(p_cur)) { +Tile *queue_pop(Queue* this) { + Tile *p_tile = this->p_first; + this->p_first = p_tile->p_next; + if (this->p_first == NULL) { + this->p_last = NULL; + } + return p_tile; +} + +/********** Algorithmus von Hopcroft und Karp **********/ +bool hk_bfs(Field *this) { + Queue q; // Schlange von Kacheln + queue_init(&q); + Tile *t = this->tiles; + for (int i = 1; i < this->num_tiles; i++) { + // nur gerade Kacheln werden zur queue hinzufuegen + if (tile_odd(&t[i])) { continue; } - if (p_cur->p_matching == NULL) { - // Freier Knoten -> Zur Schlange hinzufuegen - p_cur->dist = 0; // Erste Spalte im Schichtgraphen - queue_push(&q, p_cur); + if (t[i].pair == 0) { + t[i].dist = 0; + queue_push(&q, &t[i]); } else { - p_cur->dist = INF; // Spaetere Spalte im Schichtgraphen (alle Kanten?) + t[i].dist = INF; } } - this->null.dist = INF; + t[0].dist = INF; while (!queue_empty(&q)) { - Tile *p_cur = queue_pop(&q); - if (p_cur->dist < INF) { - for (int i = 0; i < 4; i++) { - Tile *p_neigh = p_cur->p_n+i; - if (p_neigh == NULL) - continue; - // Kante noch nicht im Schichtgraphen? - if(p_neigh->dist == INF) { - Tile *matching = p_neigh->p_matching; - if (matching == NULL) { - return true; // Es gibt einen augmentierenden Pfad - } - matching->dist = p_cur->dist + 1; - queue_push(&q, matching); - } + Tile *e = queue_pop(&q); // nehme naechste gerade Kachel + if (e->dist >= t[0].dist) + continue; + for (int i = 0; i < 4; i++) { + Tile* p_neigh = &t[e->neigh[i]]; + Tile* p_pair = &t[p_neigh->pair]; + if(p_pair->dist == INF) { + p_pair->dist = e->dist+1; + queue_push(&q, p_pair); } } } - return false; + return t[0].dist != INF; } -bool hk_dfs(Tile *this) { - if (this == NULL) +bool hk_dfs(Field *this, uint32_t e) { + if (e == 0) return true; - + Tile *t = this->tiles; + Tile *p_even = &t[e]; for (int i = 0; i < 4; i++) { - Tile *p_neigh = this->p_n+i; // Benachbart zu odd + // Benachbart zu e + uint32_t o = p_even->neigh[i]; // Nachbar, ungerade Kachel + Tile* p_odd = &t[o]; + if (t[p_odd->pair].dist == p_even->dist+1) { + // Augmentiere den Pfad, falls durch Tiefensuche gefunden + if (hk_dfs(this, p_odd->pair)) { + p_even->pair = o; + p_odd->pair = e; + return true; + } + } } + // Kein augmentierender Pfad von e aus + p_even->dist = INF; return false; } -int main (void) -{ - // erstellen des Liste zum parsen des inputs - List tile_list; - list_init(&tile_list); // Liste ist owner von Tiles - ReadResult result = parse_input(&tile_list); // lesen des Inputs - switch (result) { - case ReadOk: - break; - case ReadEof: - // bei leerer Eingabe nichts ausgeben - return EXIT_SUCCESS; - case ReadErrIntegerOverflow: - fprintf(stderr, "Error in line %d: too big integer\n", tile_list.num_tiles); - list_free(&tile_list); - return EXIT_FAILURE; - case ReadErrNonDigitCharacter: - fprintf(stderr, "Error in line %d: invalid character\n", tile_list.num_tiles); - list_free(&tile_list); - return EXIT_FAILURE; - case ReadErrTooFewNumbers: - fprintf(stderr, "Error in line %d: Too few numbers, expected exactly 2\n", - tile_list.num_tiles); - list_free(&tile_list); - return EXIT_FAILURE; - case ReadErrTooManyNumbers: - fprintf(stderr, "Error in line %d: Too much numbers, expected exactly 2\n", - tile_list.num_tiles); - list_free(&tile_list); - return EXIT_FAILURE; - case ReadErrOutOfMemory: - fprintf(stderr, "Error in line %d: Failed to allocate more memory", - tile_list.num_tiles); - list_free(&tile_list); - return EXIT_FAILURE; +void hk_print(Field *this) { + Tile *t = this->tiles; + for (uint32_t i = 1; i < this->num_tiles; i++) { + //printf("%u\n", i); + if (this->tiles[i].pair == 0) { + printf("None\n"); + return; + } } - - Array tile_array; - // uebertragen der Liste in ein Array, und uebergeben des ownership der Tiles - // an das Array - if(array_from_list(&tile_array, &tile_list) == MallocFailed) { - fprintf(stderr, "Error: Failed to allocate enough memory"); - list_free(&tile_list); // fehlgeschlagen, noch ist liste owner. - return EXIT_FAILURE; + for (uint32_t i = 1; i < this->num_tiles; i++) { + if (tile_odd(&t[i])) + continue; + uint32_t p = t[i].pair; + printf("%u %u;%u %u\n", t[i].x, t[i].y, t[p].x, t[p].y); } +} - // ignoriert null-tile - qsort(tile_array.tiles, tile_array.num_tiles-1, sizeof(Tile*), tile_compare); - - if(array_find_neighbours(&tile_array)) { - fprintf(stderr, "Error: Duplicated entry\n"); - array_drop(&tile_array); - return EXIT_FAILURE; +void hk(Field *this) { + uint32_t result = 0; + while(hk_bfs(this)) { + for (uint32_t i = 1; i < this->num_tiles; i++) { + if (tile_odd(&this->tiles[i])) + continue; + if (this->tiles[i].pair == 0 && hk_dfs(this, i)) + result++; + } } + hk_print(this); +} - // Check nach Validitaet erst nach Suche nach Dopplungen moeglich - if (!list_necessity(&tile_list)) { - printf("None\n"); - array_drop(&tile_array); - return EXIT_SUCCESS; +int main() { + Field f; + if(field_init(&f)) { + fprintf(stderr, "Failed to allocate memory"); + return EXIT_FAILURE; } - - // check nach Rechteck erst nach check fuer Doppelungen moeglich - if (list_rectangle(&tile_list)) { - list_print_rectangle(&tile_list); - array_drop(&tile_array); - return EXIT_SUCCESS; + int result = EXIT_FAILURE; + switch(field_parse(&f)) { + case ReadOk: + qsort(f.tiles+1, f.num_tiles-1, sizeof(Tile), tile_compare); + if (field_neighbours(&f) != 0) { + fprintf(stderr, "Error: Duplicated entry\n"); // Duplikat exisitert + break; + } + if (f.num_tiles - f.num_odd == f.num_odd) { + printf("None\n"); + } + hk(&f); // Algorithmus von Hopcroft und Karp + result = EXIT_SUCCESS; + break; + case ReadEof: result = EXIT_SUCCESS; break; + case ReadErrOverflow: fprintf(stderr, "%u: too big integer\n", f.num_tiles); break; + case ReadErrInvalidChar: fprintf(stderr, "%u: invalid character\n", f.num_tiles); break; + case ReadErrTooFewNumbers: fprintf(stderr, "%u: too few numbers\n", f.num_tiles); break; + case ReadErrTooManyNumbers: fprintf(stderr, "%u: too many numbers\n", f.num_tiles); break; + case ReadErrOutOfMemory: fprintf(stderr, "%u: not enough memory\n", f.num_tiles); break; } - - // Algorithmus von Hopcroft und Karp - - - array_drop(&tile_array); - return EXIT_SUCCESS; + free(f.tiles); + return result; } diff --git a/loesung2.c b/loesung2.c deleted file mode 100755 index 5b37b0b..0000000 --- a/loesung2.c +++ /dev/null @@ -1,378 +0,0 @@ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> // fixed sized integer -#include <stdbool.h> // booleans - -#define INF UINT32_MAX - -/********** Kachel definition **********/ -typedef struct Tile { - uint32_t x; - uint32_t y; - uint32_t neigh[4]; // Nachbarn - struct Tile *p_next; // queue - uint32_t pair; // matching partner - uint32_t dist; // entfernung zu Knoten 0 im Schichtgraph -} Tile; - -// initialisieren des Speichers von einem Tile -void tile_init(Tile *this) { - memset(this, 0, sizeof(Tile)); - this->dist = INF; -} - -int tile_compare(const void *p, const void *q) { - const Tile *s = (const Tile*) p; - const Tile *t = (const Tile*) q; - // als erstes nach x sortieren - if (s->x < t->x) return -1; - if (s->x > t->x) return 1; - // danach nach y sortieren - if (s->y < t->y) return -1; - if (s->y > t->y) return 1; - return 0; // Elemente sind gleich -} - -// Kacheln wie im Schachbrettmuster einordnen -uint32_t tile_odd(Tile* this) { - return ((this->x ^ this->y)&1); -} - -/********** Kachelfeld **********/ -typedef struct Field { - // Array von Tiles, tile 0 is imagenary tile for hk-algorithmus - // Tiles werden mit 1 bis num_tiles exklusive indiziert - Tile *tiles; - uint32_t num_tiles; - uint32_t size; - uint32_t num_odd; -} Field; - -// returns 0 if successful, nonzero if failed -int field_init(Field *this) { - memset(this, 0, sizeof(Field)); - this->tiles = malloc(sizeof(Tile)); - this->num_tiles = 1; - this->size = 1; - return this->tiles == 0; -} - -// if an error occurs, all memory get freed -int field_push(Field *this, Tile *p_tile) { - if (this->size == this->num_tiles) { - if (this->size == 1u<<31) return 1; // catch overflow - this->size *= 2; // Armortisiert O(1) - Tile *new = realloc(this->tiles, this->size*sizeof(Tile)); - if (new == NULL) return 1; // catch failed realloc - this->tiles = new; - } - this->num_odd += tile_odd(p_tile); - memcpy(this->tiles+this->num_tiles, p_tile, sizeof(Tile)); - this->num_tiles++; - return 0; -} - -/** Parsen einer Kachel(Tile) aus einer Zeile von StdIn - * - * Die Werte werden in die uebergebene Kachel geschrieben, sind aber - * nur gueltig, wenn der Rueckgabewert `ReadOk` ist. - * - * Voraussetzung: p_tile muss initialisiert sein - */ -typedef enum ReadResult { - ReadOk, - ReadEof, - ReadErrOverflow, - ReadErrInvalidChar, - ReadErrTooFewNumbers, - ReadErrTooManyNumbers, - ReadErrOutOfMemory, -} ReadResult; -ReadResult read_line(Tile* p_tile){ - int c = getchar(); - if (c == EOF) { - return ReadEof; - } - int cur_number = 0; - bool cur_whitespace = true; - uint32_t *p_cur; // aktuell zu parsende Zahl - while(1) { - if ('0' <= c && c <= '9') { - if (cur_whitespace) { - if(cur_number == 2) { - return ReadErrTooManyNumbers; - } - p_cur = (&p_tile->x)+cur_number; - cur_whitespace = false; - cur_number++; - } - // 429496730 = 2^32 / 10, daher wenn `p_cur` groesser ist, wird ein - // overflow erzeugt - if (*p_cur > 429496729) { - return ReadErrOverflow; - } - (*p_cur) *= 10; - int digit = c - '0'; - if (*p_cur > UINT32_MAX - digit) { - return ReadErrOverflow; - } - (*p_cur) += digit; - } else if (c == ' ') { - cur_whitespace = true; - } else if (c == '\n') { - if (cur_number == 2) { - return ReadOk; - } else { - return ReadErrTooFewNumbers; - } - } else { - return ReadErrInvalidChar; - } - c = getchar(); // get next character - } -} - -/** Liest das Input von StdIn und schreibt das Ergebnis in die uebergebene Liste - * - * Laufzeit: O(n) - * Speicherbedarf: O(n) - * - * Return: - * - ReadResult: - * ReadOk, falls das lesen Erfolgreich war - * ReadErr..., falls die Eingabe ungueltig ist oder zu wenig Speicher vorhanden. - * `num_tiles` indiziert die Zeile, in der der Fehler aufgetreten ist - */ -ReadResult field_parse(Field *this) { - while (1) { - Tile next; - tile_init(&next); - ReadResult result = read_line(&next); - switch (result) { - case ReadOk: - // einfuegen in die Liste - if (field_push(this, &next)) { - return ReadErrOutOfMemory; - } - break; - case ReadEof: - if (this->num_tiles == 1) { - return ReadEof; - } else { - return ReadOk; - } - default: // error - return result; - } - } -} - -/** Setzen der Nachbarn der Kacheln - * Rueckgabe: 0 falls alles ok - * 1 falls Dopplungen vorkommen - */ -int field_neighbours(Field *this) { - uint32_t top = 1; // vergleich mit oberer Zeile - uint32_t begin_line = 1; // start der aktuellen Zeile - Tile *t = this->tiles; - for (uint32_t cur = 2; cur < this->num_tiles; cur++) { - // ermitteln der x-Beziehung - uint32_t east = cur-1; - if (t[cur].x == t[east].x) { // gleiche Zeile - if (t[cur].y == t[east].y) { // gleiche Spalte - return 1; // Doppelung - } else if (t[cur].y-1 == t[east].y) { - t[cur].neigh[1] = east; - t[east].neigh[3] = cur; - } - } else { - top = begin_line; - begin_line = cur; // neue Zeile - } - // ermitteln der Zeilen-Beziehung - if (t[begin_line].x != 0 && t[top].x < t[begin_line].x - 1) { - // Zeilensprung => Warten bis zur naechsten Zeile angekommen - } else if (t[top].x == t[cur].x - 1) { - // finden, ob paar nach oben existiert O(n) fuer alle Nachbarn nach oben/unten. - for(;t[top].y < t[cur].y && top < begin_line; top++); - - // aktuelle obere Kachel koennte benachbart sein - if (t[top].y == t[cur].y) { // nicht auf naechste Zeile uebergegangen - // Neue Verbindung oben/unten gefunden - t[top].neigh[2] = cur; - t[cur].neigh[0] = top; - } - } - } - return 0; -} - -void field_print(Field *this) { - printf("[\n"); - Tile *t = this->tiles; - for (uint32_t i = 1; i < this->num_tiles; i++){ - printf("\t(%u %u): {", t[i].x, this->tiles[i].y); - for (int j = 0; j < 4; j++) { - if(t[i].neigh[j] != 0) { - Tile *neigh = &t[t[i].neigh[j]]; - printf(" (%u %u)", neigh->x, neigh->y); - } - } - printf(" }\n"); - } - printf("]\n"); -} - -/********** Schlange von Tiles **********/ -typedef struct Queue { - Tile *p_first; - Tile *p_last; -} Queue; - -void queue_init(Queue* this) { - this->p_first = NULL; - this->p_last = NULL; -} - -void queue_push(Queue* this, Tile* p_tile) { - if (this->p_last != NULL) { - this->p_last->p_next = p_tile; - } else { - this->p_first = p_tile; - } - this->p_last = p_tile; - p_tile->p_next = NULL; -} - -bool queue_empty(Queue* this) { - return this->p_first == NULL; -} - -Tile *queue_pop(Queue* this) { - Tile *p_tile = this->p_first; - this->p_first = p_tile->p_next; - if (this->p_first == NULL) { - this->p_last = NULL; - } - return p_tile; -} - -/********** Algorithmus von Hopcroft und Karp **********/ -bool hk_bfs(Field *this) { - Queue q; // Schlange von Kacheln - queue_init(&q); - Tile *t = this->tiles; - for (int i = 1; i < this->num_tiles; i++) { - // nur gerade Kacheln werden zur queue hinzufuegen - if (tile_odd(&t[i])) { - continue; - } - if (t[i].pair == 0) { - t[i].dist = 0; - queue_push(&q, &t[i]); - } else { - t[i].dist = INF; - } - } - t[0].dist = INF; - while (!queue_empty(&q)) { - Tile *e = queue_pop(&q); // nehme naechste gerade Kachel - if (e->dist >= t[0].dist) - continue; - for (int i = 0; i < 4; i++) { - Tile* p_neigh = &t[e->neigh[i]]; - Tile* p_pair = &t[p_neigh->pair]; - if(p_pair->dist == INF) { - p_pair->dist = e->dist+1; - queue_push(&q, p_pair); - } - } - } - return t[0].dist != INF; -} - -bool hk_dfs(Field *this, uint32_t e) { - if (e == 0) - return true; - Tile *t = this->tiles; - Tile *p_even = &t[e]; - for (int i = 0; i < 4; i++) { - // Benachbart zu e - uint32_t o = p_even->neigh[i]; // Nachbar, ungerade Kachel - Tile* p_odd = &t[o]; - if (t[p_odd->pair].dist == p_even->dist+1) { - // Augmentiere den Pfad, falls durch Tiefensuche gefunden - if (hk_dfs(this, p_odd->pair)) { - p_even->pair = o; - p_odd->pair = e; - return true; - } - } - } - // Kein augmentierender Pfad von e aus - p_even->dist = INF; - return false; -} - -void hk_print(Field *this) { - Tile *t = this->tiles; - for (uint32_t i = 1; i < this->num_tiles; i++) { - //printf("%u\n", i); - if (this->tiles[i].pair == 0) { - printf("None\n"); - return; - } - } - for (uint32_t i = 1; i < this->num_tiles; i++) { - if (tile_odd(&t[i])) - continue; - uint32_t p = t[i].pair; - printf("%u %u;%u %u\n", t[i].x, t[i].y, t[p].x, t[p].y); - } -} - -void hk(Field *this) { - uint32_t result = 0; - while(hk_bfs(this)) { - for (uint32_t i = 1; i < this->num_tiles; i++) { - if (tile_odd(&this->tiles[i])) - continue; - if (this->tiles[i].pair == 0 && hk_dfs(this, i)) - result++; - } - } - hk_print(this); -} - -int main() { - Field f; - if(field_init(&f)) { - fprintf(stderr, "Failed to allocate memory"); - return EXIT_FAILURE; - } - int result = EXIT_FAILURE; - switch(field_parse(&f)) { - case ReadOk: - qsort(f.tiles+1, f.num_tiles-1, sizeof(Tile), tile_compare); - if (field_neighbours(&f) != 0) { - fprintf(stderr, "Error: Duplicated entry\n"); // Duplikat exisitert - break; - } - if (f.num_tiles - f.num_odd == f.num_odd) { - printf("None\n"); - } - hk(&f); // Algorithmus von Hopcroft und Karp - result = EXIT_SUCCESS; - break; - case ReadEof: result = EXIT_SUCCESS; break; - case ReadErrOverflow: fprintf(stderr, "%u: too big integer\n", f.num_tiles); break; - case ReadErrInvalidChar: fprintf(stderr, "%u: invalid character\n", f.num_tiles); break; - case ReadErrTooFewNumbers: fprintf(stderr, "%u: too few numbers\n", f.num_tiles); break; - case ReadErrTooManyNumbers: fprintf(stderr, "%u: too many numbers\n", f.num_tiles); break; - case ReadErrOutOfMemory: fprintf(stderr, "%u: not enough memory\n", f.num_tiles); break; - } - free(f.tiles); - return result; -} -- GitLab