#include #include #include #define MAX 256 #define INFTY 10000 // Nekonečno struct vrchol { // Vrchol trie struct vrchol *syn[2]; // syn[0] pro tečku, syn[1] pro čárku struct slovo *slova; // Seznam slov, která tu končí int hloubka; // Délka morseovkového zápisu (hloubka v trii) }; struct vrchol koren; struct slovo { // Takhle si ukládáme seznamy slov struct slovo *dalsi; // Vlastně by si stačilo pamatovat jen jedno slovo, char s[1]; // ale třeba se to bude hodit v následující úloze :) }; // Tabulka kódů: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z char morse[26] = { 6,17,21, 9, 2,20,11,16, 4,30,13,18, 7, 5,15,22,27,10, 8, 3,12,24,14,25,29,19 }; void preloz(char *co, char *kam) // Přeloží slovo do morseovky { while (*co) { int k = morse[*co++ - 'a']; // Ďábelský kód písmenka while (k > 1) { // Postupně rozkládáme na značky *kam++ = ".-"[k%2]; k /= 2; } } *kam = 0; } void nacti_slovnik(void) { char slovo[MAX], mslovo[MAX]; while (fgets(slovo, sizeof(slovo), stdin) && slovo[0] != '\n') { int len = strlen(slovo); slovo[len-1] = 0; // Smažeme konec řádku preloz(slovo, mslovo); // Přeložíme do morseovky struct vrchol *v = &koren; // Přidáváme do trie for (char *c=mslovo; *c; c++) { int z = (*c == '-'); // Aktuální značka if (!v->syn[z]) { // Kam dál? Není-li kam, založíme nový vrchol v->syn[z] = (vrchol*) malloc(sizeof(struct vrchol)); memset(v->syn[z], 0, sizeof(struct vrchol)); v->syn[z]->hloubka = v->hloubka + 1; } v = v->syn[z]; // Vydáme se tím směrem } struct slovo *s = (struct slovo*) malloc(sizeof(struct slovo) + len); // Stojíme ve vrcholu, který odpovídá konci slova, s->dalsi = v->slova; // tak tam slovo přidáme v->slova = s; strcpy(s->s, slovo); } } int B[MAX+1][MAX+1]; /* B[i][j]==1 pokud lze pokrýt [i...N-1] přesně j slovy */ //Zde pomocí dynamického programování naplníme B void SpoctiB(char *vstup, int N) { B[N][0] = 1; for (int i=N-1; i>=0; i--) //Postupujeme od konce vstupu { struct vrchol *v = &koren; //a procházíme v trii postupně od kořene int j = i; while (v && j < N) { v = v->syn[vstup[j++] == '-']; if (v && v->slova) //ano, nějaké slovo zde končí for (int k=0; k= N) //Rozklad této větve výpočtu je již dokončen { *p = 0; puts(rozklad); K_hotovo++; return; } struct vrchol *v = &koren; *p++ = ' '; while (v && i < N) { v = v->syn[vstup[i++] == '-']; if (v && v->slova && B[i][j-1]) //končí-li zde nějaké slovo for (struct slovo *slovo = v->slova; slovo; slovo=slovo->dalsi) { //pak projdeme všechna taková slova int delka = strlen(slovo->s); memcpy(p, slovo->s, delka); //dopíšeme si je k částečnému rozkladu PisReseni(rozklad, p + delka, vstup, i, N, j-1); //a rekurzivně pokračujeme if(K_hotovo == K) //a jestli jich už máme dost, skončíme return; } } } int main(void) { char z[MAX]; // Vstupní řetězec int n; // Jeho délka struct vrchol *s[MAX+1]; nacti_slovnik(); // Přečteme slovník a vstup fgets(z, MAX, stdin); // Pozor, indexujeme od 1 n = strlen(z)-1; scanf("%d", &K); //Načteme, kolik rozkladů se po nás chce K_hotovo = 0; SpoctiB(z, n); char rozklad[MAX]; for(int j=0; j<=n && K_hotovo