#include #include #include /** * Vzorový program pro 28-2-4 Útěk z města * Předpokládaný formát vstupu: * na prvním řádku dvě čísla R S, udávající počet řádků a sloupců v síti * na dalších R řádcích vždy S znaků označujících, co je na daném místě sítě: * B budova * P pobočka banky * - průchozí pole * * Program připraví graf a spustí na něm Fordům-Fulkersonův algoritmus * * Z implementačních důvodů se okolo sítě přidává na každé straně ještě jedna * řada políček. Políčka jsou implicitně očíslovaná (v pořadí primárně podle řádků * a sekundárně podle sloupců), označení vstupních vrcholů odpovídá očíslování * políček, označení výstupních vrcholů je posunuté o celkový počet políček (tedy * v síti 3x4 patří ke vstupnímu vrcholu 5 výstupní vrchol 17). **/ struct hrana { int odkud; int kam; int kapacita; // kapacita tak, jak s ní pracuje FF int tok; int cesta; // technikální věc, pořadové číslo cesty, při jejímž hledání byla hrana naposledy použita struct hrana *opacna; }; struct seznam_hran { struct hrana *hrana; struct seznam_hran *dalsi; }; // Narovinu, na tohle by bylo řádově hezčí použít vektor z C++… #define MAX_P 1000000 int pobocky[MAX_P]; struct seznam_hran *cesty[MAX_P]; // … a na tohle taky #define MAX_N 1000000 struct seznam_hran *sousedi[MAX_N]; int pocet; // celkový počet políček, používá se k přepočtu vstupní->výstupní vrchol int iterace; // iterace, resp. pořadí zlepšující cesty, kterou hledáme void pridej_souseda(int odkud, struct hrana *hrana) { struct seznam_hran *soused = malloc(sizeof(struct seznam_hran)); soused->hrana = hrana; soused->dalsi = sousedi[odkud]; sousedi[odkud] = soused; } void pridej_hranu(int odkud, int kam) { struct hrana *h1 = malloc(sizeof(struct hrana)); struct hrana *h2 = malloc(sizeof(struct hrana)); // Přidáme hranu a pro jednoduchou implementaci FF také opačnou hranu s nulovou kapacitou // Tohle si můžeme dovolit, protože máme jistotu, že opačná hrana v grafu neexistuje, // jinak by párování hran muselo být řádově opatrnější h1->odkud = odkud; h1->kam = kam; h1->kapacita = 1; h1->tok = 0; h1->cesta = -1; h2->odkud = kam; h2->kam = odkud; h2->kapacita = 0; h2->tok = 0; h2->cesta = -1; h1->opacna = h2; h2->opacna = h1; pridej_souseda(odkud, h1); pridej_souseda(kam, h2); } void pridej_vrchol(int ind) { pridej_hranu(ind, ind+pocet); } struct seznam_hran *vrat_hrany(int odkud) { return sousedi[odkud]; } struct seznam_hran *najdi_cestu(int odkud, int kam, struct seznam_hran *cesta, int iterace) { if (odkud == kam) return cesta; struct seznam_hran *hrany = vrat_hrany(odkud); while (hrany) { struct hrana *hrana = hrany->hrana; // Kontrola `iterace > hrana->cesta` nám šetří vyhledávání v cestě, tj. seznamu hra, // které by bylo lineární if (hrana->kapacita - hrana->tok > 0 && iterace > hrana->cesta) { // Převážně Cčková technikálie, prostě přidáváme další hranu do seznamu struct seznam_hran *ncesta = malloc(sizeof(struct seznam_hran)); ncesta->hrana = hrana; ncesta->dalsi = cesta; hrana->cesta = iterace; struct seznam_hran *pokracovani = najdi_cestu(hrana->kam, kam, ncesta, iterace); if (pokracovani) { return pokracovani; } free(ncesta); // Cčková technikálie, ať neztrácíme tolik paměti } hrany = hrany->dalsi; } return NULL; } int ford_fulkerson(int zdroj, int stok) { struct seznam_hran *cesta = najdi_cestu(zdroj, stok, NULL, iterace); iterace++; while (cesta) { struct seznam_hran *hrany = cesta; struct hrana *akt; int zmena = INT_MAX; while (hrany) { akt = hrany->hrana; if (zmena > akt->kapacita - akt->tok) zmena = akt->kapacita - akt->tok; hrany = hrany->dalsi; } hrany = cesta; while (hrany) { akt = hrany->hrana; akt->tok += zmena; akt->opacna->tok -= zmena; struct seznam_hran *swp = hrany; hrany = hrany->dalsi; free(swp); // Cčková technikálie, ať neztrácíme tolik paměti } cesta = najdi_cestu(zdroj, stok, NULL, iterace); iterace++; } struct seznam_hran *hrany = vrat_hrany(zdroj); int cena = 0; while (hrany) { cena += hrany->hrana->tok; hrany = hrany->dalsi; } return cena; } // Primárně debugovací kus kódu :) void vypis_cestu(struct seznam_hran *hrany) { printf("%d", hrany->hrana->odkud); while (hrany) { printf(" -> %d", hrany->hrana->kam); hrany = hrany->dalsi; } printf("\n"); } struct seznam_hran *cesta_do_cile(int odkud, int kam) { struct seznam_hran *cesta = NULL, *akt = NULL; struct seznam_hran *hrany = vrat_hrany(odkud); while (hrany) { // Z toho, jak jsme postavili graf, víme, že z každého políčka povede // maximálně jedna hrana, po které někdo utíká, ergo můžeme hledat prostě // první hranu s kladným tokem if (!(hrany->hrana->tok > 0)) { hrany = hrany->dalsi; continue; } if (!cesta) cesta = akt = malloc(sizeof(struct seznam_hran)); else { akt->dalsi = malloc(sizeof(struct seznam_hran)); akt = akt->dalsi; } akt->hrana = hrany->hrana; akt->dalsi = NULL; if (hrany->hrana->kam == kam) return cesta; hrany = vrat_hrany(hrany->hrana->kam); } return NULL; } void urci_cesty(int p, int *pobocky, int stok) { for (int i=0; ihrana->kapacita) printf(" %d", hrany->hrana->kam); hrany = hrany->dalsi; } printf("\n"); } } void vypis_cesty(int p) { for (int i=0; i