From 15bc156b02145aa112db8484c57544522c5da900 Mon Sep 17 00:00:00 2001
From: Manuel Bucher <manuel.bucher@hu-berlin.de>
Date: Fri, 22 Jun 2018 00:23:42 +0200
Subject: [PATCH] added new solution

---
 Makefile   |   6 +-
 loesung.c  | 163 +++++++++++++++++++-----
 loesung2.c | 357 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 491 insertions(+), 35 deletions(-)
 create mode 100755 loesung2.c

diff --git a/Makefile b/Makefile
index 742516b..ebb9bf3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,12 @@
-all: loesung
+all: loesung2
 
 WARNINGS = -Wall #-Werror
 OPTIONAL = -Wextra -Wpedantic -Wshadow
 DEBUG = -g -ggdb -fno-omit-frame-pointer
 OPTIMIZE = -Og -std=c11
 
-loesung: Makefile loesung.c
-	$(CC) -o $@ $(WARNINGS) $(OPTIONAL) $(DEBUG) $(OPTIMIZE) loesung.c
+loesung: Makefile loesung2.c
+	$(CC) -o $@ $(WARNINGS) $(OPTIONAL) $(DEBUG) $(OPTIMIZE) loesung2.c
 clean:
 	rm -f loesung
 
diff --git a/loesung.c b/loesung.c
index cbcc3d2..0f10c42 100644
--- a/loesung.c
+++ b/loesung.c
@@ -4,31 +4,32 @@
 #include <stdint.h> // fixed sized integer
 #include <stdbool.h> // booleans
 
+#define INF UINT32_MAX
+
 typedef struct Tile {
     uint32_t x;
     uint32_t y;
-    struct Tile *p_next; // used for list
-    struct Tile *p_n; // north
+    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;
 } Tile;
 
 
 // Reservieren und initialisieren des Speicherplatz eines Tiles
-Tile* tile_new() {
-    Tile *p_tile = malloc(sizeof(Tile));
-    if(p_tile == NULL) { // failed to allocate memory
-        return NULL;
-    }
-    p_tile->x = 0;
-    p_tile->y = 0;
-    p_tile->p_next = NULL;
-    p_tile->p_n = NULL;
-    p_tile->p_e = NULL;
-    p_tile->p_s = NULL;
-    p_tile->p_w = NULL;
-    return p_tile;
+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;
+    this->dist = INF;
 }
 
 int tile_compare(const void *p, const void *q) {
@@ -47,6 +48,9 @@ int tile_compare(const void *p, const void *q) {
     return 0; // Elemente sind gleich
 }
 
+inline bool tile_is_odd(Tile* this) {
+    return ((this->x ^ this->y)&1) != 0;
+}
 
 /*************** List von Tiles *********************/
 /** List von Tiles */
@@ -87,7 +91,7 @@ void list_push(List *this, Tile *p_tile) {
     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 += (p_tile->x - p_tile->y)&1;
+    this->num_odd += tile_is_odd(p_tile);
 }
 
 /** Freigeben des reservierten Speichers von der Liste
@@ -144,6 +148,51 @@ void list_print_rectangle(List *this) {
     }
 }
 
+/** 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;
+}
+
+/** 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.
+ *
+ * Voraussetzung: p_tile muss initialisiert sein
+ */
 typedef enum ReadResult {
     ReadOk,
     ReadEof,
@@ -153,13 +202,6 @@ typedef enum ReadResult {
     ReadErrTooManyNumbers,
     ReadErrOutOfMemory,
 } ReadResult;
-/** 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.
- *
- * Voraussetzung: p_tile muss initialisiert sein
- */
 ReadResult read_line(Tile* p_tile){
     int c = getchar();
     if (c == EOF) {
@@ -225,10 +267,11 @@ ReadResult read_line(Tile* p_tile){
  */
 ReadResult parse_input(List *this) {
     while (1) {
-        Tile *p_tile = tile_new(); // neues Element erstellen
+        Tile *p_tile = malloc(sizeof(Tile));
         if (p_tile == NULL) {
             return ReadErrOutOfMemory;
         }
+        tile_init(p_tile);
         ReadResult result = read_line(p_tile);
         switch (result) {
         case ReadOk:
@@ -252,6 +295,7 @@ ReadResult parse_input(List *this) {
  */
 typedef struct Array {
     uint32_t num_tiles;
+    Tile null;
     Tile* (*tiles);
 } Array;
 
@@ -259,7 +303,7 @@ typedef struct Array {
  * inklusive der Tiles */
 void array_drop(Array *this) {
     if(this->tiles != NULL) {
-        for(uint32_t i = 0; i < this->num_tiles; i++) {
+        for(uint32_t i = 1; i < this->num_tiles; i++) {
             free(this->tiles[i]);
         }
         free(this->tiles);
@@ -275,13 +319,15 @@ typedef enum MallocResult {
  * Laufzeit: O(n)
  */
 MallocResult array_from_list(Array *this, List* p_list) {
-    this->tiles = malloc(p_list->num_tiles * sizeof(Tile*));
+    this->num_tiles = p_list->num_tiles+1;
+    this->tiles = malloc(this->num_tiles * sizeof(Tile*));
     if(this->tiles == NULL) {
         return MallocFailed;
     }
-    this->num_tiles = p_list->num_tiles;
+    tile_init(&this->null); // create null tile for hk
+    this->tiles[0] = &this->null;
     Tile *cur = p_list->p_top;
-    for (uint32_t i = 0; i < this->num_tiles; i++) {
+    for (uint32_t i = 1; i < this->num_tiles; i++) {
         this->tiles[i] = cur;
         cur = cur->p_next;
         this->tiles[i]->p_next = NULL;
@@ -296,9 +342,9 @@ MallocResult array_from_list(Array *this, List* p_list) {
  *            1 falls Dopplungen vorkommen TODO: enum
  */
 int array_find_neighbours(Array *this) {
-    uint32_t i = 0; // vergleich mit oberer Zeile
-    uint32_t begin_line = 0;
-    for (uint32_t j = 1; j < this->num_tiles; j++) {
+    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
@@ -337,6 +383,57 @@ void array_print(Array *this) {
     }
 }
 
+/* algorithmus von Hopcroft und Karp */
+bool hk_bfs(Array *this) {
+    Queue q;
+    queue_init(&q); // queue von odd Tiles
+
+    for (int i = 0; i < this->num_tiles; i++) {
+        Tile *p_cur = this->tiles[i];
+        if (tile_is_odd(p_cur)) {
+            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);
+        } else {
+            p_cur->dist = INF; // Spaetere Spalte im Schichtgraphen (alle Kanten?)
+        }
+    }
+    this->null.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);
+                }
+            }
+        }
+    }
+    return false;
+}
+
+bool hk_dfs(Tile *this) {
+    if (this == NULL)
+        return true;
+
+    for (int i = 0; i < 4; i++) {
+        Tile *p_neigh = this->p_n+i; // Benachbart zu odd
+    }
+    return false;
+}
+
 int main (void)
 {
     // erstellen des Liste zum parsen des inputs
@@ -383,7 +480,8 @@ int main (void)
         return EXIT_FAILURE;
     }
 
-    qsort(tile_array.tiles, tile_array.num_tiles, sizeof(Tile*), tile_compare);
+    // 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");
@@ -407,6 +505,7 @@ int main (void)
 
     // Algorithmus von Hopcroft und Karp
 
+
     array_drop(&tile_array);
     return EXIT_SUCCESS;
 }
diff --git a/loesung2.c b/loesung2.c
new file mode 100755
index 0000000..a7ddbe3
--- /dev/null
+++ b/loesung2.c
@@ -0,0 +1,357 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h> // fixed sized integer
+#include <stdbool.h> // booleans
+
+#define INF UINT32_MAX
+
+/** 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; }
+
+/********** 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;
+} 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 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;
+    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;
+    // TODO: Rechteck erkennen?
+} 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;
+        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 ost/west-Beziehung
+        if (t[cur].y == t[cur-1].y) {
+            if (t[cur].x == t[cur-1].x) {
+                return 1; // Doppelung
+            }
+            if (t[cur].x == t[cur-1].x - 1) {
+                t[cur].neigh[1] = cur-1;
+                t[cur-1].neigh[3] = cur;
+            }
+        } else {
+            begin_line = cur; // neue Zeile
+        }
+        // ermitteln der nord/sued-Beziehung
+        if (t[top].y < t[cur].y - 1) {
+            top = begin_line; // Luecke zwischen zeilen
+        } else if (t[top].y == t[cur].y - 1) {
+            // finden, ob paar existiert, zurzeit O(n).
+            for(;t[top].y < t[cur].y && top < begin_line; top++);
+            if (t[top].x == t[cur].x) {
+                t[top].neigh[2] = cur;
+                t[cur].neigh[0] = top;
+            }
+        }
+    }
+    return 0;
+}
+
+/********** 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 Knoten
+    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, ungerades Tile
+        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)) {
+                printf("%u %u\n", e, o);
+                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) {
+    for (uint32_t i = 1; i < this->num_tiles; i++) {
+        printf("%u\n", i);
+        if (this->tiles[i].pair == 0) {
+            printf("None\n");
+            return; // Kein Belegung existiert
+        }
+    }
+}
+
+void hk(Field *this) {
+    uint32_t result = 0;
+    while(hk_bfs(this)) {
+        for (int 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, "%d: too big integer\n", f.num_tiles); break;
+    case ReadErrInvalidChar:    fprintf(stderr, "%d: invalid character\n", f.num_tiles); break;
+    case ReadErrTooFewNumbers:  fprintf(stderr, "%d: too few numbers\n", f.num_tiles); break;
+    case ReadErrTooManyNumbers: fprintf(stderr, "%d: too many numbers\n", f.num_tiles); break;
+    case ReadErrOutOfMemory:    fprintf(stderr, "%d: failed to allocate more memory\n", f.num_tiles); break;
+    }
+    free(f.tiles);
+    return result;
+}
-- 
GitLab