#include #include #include #include /* * A trie. */ enum { NCHILDREN = 'z' - 'a' + 1 }; struct trie_node { char *key; struct trie_node *children[NCHILDREN]; }; /* Timus must be compiling with -ansi - strdup gives a compilation error. */ static char * my_strdup(const char *p) { char *q = malloc(strlen(p) + 1); strcpy(q, p); return q; } static void trie_insert(struct trie_node **ptrie, const char *word) { const char *p; for (p = word; ;++p) { struct trie_node *trie; if ((trie = *ptrie) == NULL) *ptrie = trie = calloc(1, sizeof *trie); if (*p == '\0') { trie->key = my_strdup(word); break; } ptrie = &trie->children[(int)(*p - 'a')]; } } static void trie_free(struct trie_node *trie) { int i; for (i = 0; i < NCHILDREN; i++) { if (trie->children[i]) trie_free(trie->children[i]); } free(trie); } /* * An iterator for words in the trie that match a sequence of digits. */ static const char *digit_to_char[] = { "oqz", "ij", "abc", "def", "gh", "kl", "mn", "prs", "tuv", "wxy" }; /* With coroutines, this mess could be replaced with much simpler recursive code... */ enum { MAX_STACK = 200 }; struct match_iterator { struct iterator_state { const struct trie_node *node; const char *digits; int state_index; } stack[MAX_STACK]; int stack_top; }; static void push_state(struct match_iterator *iter, const struct trie_node *node, const char *digits, int state_index) { struct iterator_state *p = &iter->stack[iter->stack_top++]; p->node = node; p->digits = digits; p->state_index = state_index; } static int pop_state(struct match_iterator *iter, const struct trie_node **node, const char **digits, int *state_index) { if (iter->stack_top <= 0) { return 0; } else { struct iterator_state *p = &iter->stack[--iter->stack_top]; *node = p->node; *digits = p->digits; *state_index = p->state_index; return 1; } } static void match_iterator_init(struct match_iterator *iter, const struct trie_node *root, const char *digits) { iter->stack_top = 0; push_state(iter, root, digits, 0); } static const char * match_iterator_next(struct match_iterator *iter) { const char *next_key; const struct trie_node *node; const char *digits; int index; next_key = NULL; while (pop_state(iter, &node, &digits, &index)) { const char *valid_chars; again: if (index == 0) { if (node->key != NULL) { push_state(iter, node, digits, index + 1); next_key = node->key; break; } ++index; } if (*digits != '\0') { valid_chars = digit_to_char[*digits - '0']; for (; valid_chars[index - 1] != '\0'; ++index) { const int ch = valid_chars[index - 1] - 'a'; if (node->children[ch] != NULL) { push_state(iter, node, digits, index + 1); node = node->children[ch]; digits++; index = 0; goto again; } } } } return next_key; } /* * The actual problem solving code. */ enum { MAXDIGITS = 120, MAXWORDLEN = 70 }; /* Find best match using dynamic programming. */ void do_test_case(const struct trie_node *trie, const char *digits) { int ndigits; static int min_words_from[MAXDIGITS + 1]; static const char *best_word_at[MAXDIGITS + 1]; int i; ndigits = strlen(digits); for (i = 0; i < ndigits; i++) { min_words_from[i] = -1; best_word_at[i] = NULL; } min_words_from[ndigits] = 0; best_word_at[ndigits] = NULL; for (i = ndigits - 1; i >= 0; i--) { struct match_iterator iter; const char *best_word = NULL; int min_words = -1; const char *p; match_iterator_init(&iter, trie, &digits[i]); while ((p = match_iterator_next(&iter)) != NULL) { int len = strlen(p); if (min_words_from[i + len] != -1) { if (min_words == -1 || 1 + min_words_from[i + len] < min_words) { min_words = 1 + min_words_from[i + len]; best_word = p; } } } min_words_from[i] = min_words; best_word_at[i] = best_word; } if (best_word_at[0] == NULL) { puts("No solution."); } else { for (i = 0; i < ndigits; i += strlen(best_word_at[i])) { if (i > 0) putchar(' '); printf("%s", best_word_at[i]); } putchar('\n'); } } int main(void) { static char digits[MAXDIGITS]; while (scanf("%s", digits) == 1 && strcmp(digits, "-1") != 0) { int nwords, i; struct trie_node *trie = NULL; scanf("%d", &nwords); for (i = 0; i < nwords; i++) { static char word[MAXWORDLEN + 1]; scanf("%s", word); trie_insert(&trie, word); } do_test_case(trie, digits); trie_free(trie); break; } return 0; }