// 28-4-4 Podivuhodný obraz // Autor programu: Jirka Setnička #include #include #include typedef struct thrana thrana; struct thrana { int index; int kam; bool pouzita; thrana *dalsi; thrana *parova; thrana *tah_predchozi; thrana *tah_dalsi; }; typedef struct tvrchol { int stupen; bool volny; thrana *hrany; thrana *ven; } tvrchol; int N, M; tvrchol *vrchol; bool *cervena_hrana; int *fronta; void pridej_hranu(int a, int b, int index) { thrana *novaA = malloc(sizeof(thrana)); thrana *novaB = malloc(sizeof(thrana)); novaA->index = novaB->index = index; novaA->kam = b; novaB->kam = a; novaA->pouzita = novaB->pouzita = false; novaA->parova = novaB; novaB->parova = novaA; novaA->dalsi = vrchol[a].hrany; novaB->dalsi = vrchol[b].hrany; vrchol[a].stupen++; vrchol[b].stupen++; vrchol[a].hrany = novaA; vrchol[b].hrany = novaB; } void navaz_hranu(thrana *aktualni, thrana *dalsi) { dalsi->pouzita = dalsi->parova->pouzita = true; dalsi->tah_predchozi = aktualni; dalsi->parova->tah_dalsi = aktualni; aktualni->tah_dalsi = dalsi; aktualni->parova->tah_predchozi = dalsi; vrchol[aktualni->kam].ven = dalsi; } // Zkonstruuje jeden cyklus Eulerovskeho tahu, zapojí ho mezi nastavené hrany void eulerovsky_tah(int start, thrana *tah_predchozi, thrana *tah_dalsi) { // Vybereme první volnou hranu thrana *prvni = vrchol[start].hrany; while (prvni->pouzita) prvni = prvni->dalsi; prvni->pouzita = prvni->parova->pouzita = true; thrana *aktualni = prvni; while (aktualni->kam != start) { // Vybereme další volnou hranu a navážeme je na sebe thrana *dalsi = vrchol[aktualni->kam].hrany; while (dalsi->pouzita) dalsi = dalsi->dalsi; navaz_hranu(aktualni, dalsi); aktualni = dalsi; } navaz_hranu(aktualni, prvni); // Zapojení do cyklu if (tah_predchozi != NULL && tah_dalsi != NULL) { navaz_hranu(tah_predchozi, prvni); navaz_hranu(aktualni, tah_dalsi); } else { // Top level cyklus zkusí obejít celý cyklus a spustí prohledání tam, // kde ještě nejsou všechny hrany použity aktualni = prvni; while (1) { int index = aktualni->kam; thrana *dalsi = vrchol[index].hrany; while (dalsi != NULL && dalsi->pouzita) dalsi = dalsi->dalsi; // Spojíme vždy před první vycházející hranu if (dalsi != NULL) eulerovsky_tah(index, vrchol[index].ven->tah_predchozi, vrchol[index].ven); aktualni = aktualni->tah_dalsi; if (aktualni == prvni) break; } } } bool projdi_komponentu(int start) { if (vrchol[start].stupen == 0) return true; // 1. Projdeme všechny vrcholy, zjistíme počet a případně zapojíme liché vrcholy do nového int pocet = 0; int max_stupen = 0; int max_stupen_index = 0; int special_index = -1; vrchol[N].stupen = 0; vrchol[N].volny = true; vrchol[N].hrany = NULL; // Vložíme první vrchol do fronty int i = 0; int j = 1; vrchol[start].volny = false; fronta[0] = start; while (i < j) { pocet++; int index = fronta[i++]; vrchol[index].volny = false; // Pokud je lichý -> přidáme hranu do speciálního vrcholu if (index < N && vrchol[index].stupen % 2 == 1) pridej_hranu(index, N, special_index--); if (max_stupen < vrchol[index].stupen) { max_stupen = vrchol[index].stupen; max_stupen_index = index; } // Přidáme ostatní ještě volné sousedy do fronty thrana *aktualni = vrchol[index].hrany; while (aktualni != NULL) { if (vrchol[aktualni->kam].volny) { fronta[j++] = aktualni->kam; vrchol[aktualni->kam].volny = false; } aktualni = aktualni->dalsi; } } // 2. Speciální případ - lichý cyklus if (max_stupen == 2 && pocet % 2 == 1) return false; // 3. Najdeme Eulerovský tah // (pokud jsme použili speciální vrchol, tak z něho, jinak z vrcholu // nejvyššího stupně) start = (vrchol[N].stupen > 0) ? N : max_stupen_index; eulerovsky_tah(start, NULL, NULL); // 4. Obarvíme podle tahu thrana *prvni = vrchol[start].hrany; thrana *aktualni = prvni; int counter = 0; while (1) { if (counter % 2 == 0 && aktualni->index >= 0) cervena_hrana[aktualni->index] = true; counter++; aktualni = aktualni->tah_dalsi; if (aktualni == prvni) break; } return true; } int main(void) { // 1. Načtení vstupu scanf("%d %d", &N, &M); vrchol = malloc(sizeof(tvrchol) * (N + 1)); fronta = malloc(sizeof(int) * (N + 1)); cervena_hrana = malloc(sizeof(bool) * M); for (int i = 0; i < N; i++) { vrchol[i].hrany = NULL; vrchol[i].volny = true; vrchol[i].stupen = 0; } for (int i = 0; i < M; i++) { int a,b; scanf("%d %d", &a, &b); pridej_hranu(a, b, i); cervena_hrana[i] = false; } // 2. Pro každou komponentu spustíme algoritmus for (int i = 0; i < N; i++) { if (vrchol[i].volny && !projdi_komponentu(i)) printf("-1\n"); } // 3. Vypíšeme barvy hran v pořadí ze vstupu for (int i = 0; i < M; i++) printf("%d\n", cervena_hrana[i]); return 0; }