#include #include #include #include #include #include #include using namespace std; unordered_set read_dictionary(const string& path) { ifstream dict(path); unordered_set set; while (dict.good()) { string word; dict >> word; for (char& c : word) { c = tolower(c); if (!isalpha(c)) { goto ct; } } if (word.size() > 1) set.insert(word); ct: 0; } return set; } vector> by_length(const unordered_set& dict) { size_t maxlen = 0; for (const string& w : dict) maxlen = max(maxlen, w.size()); vector> by_length(maxlen+1); for (const string& w : dict) { by_length[w.size()].insert(w); } return by_length; } class Trie { struct TrieNode; struct TrieNode { vector> children; char c; TrieNode() : children(static_cast('z'-'a' + 1)) {} }; unique_ptr root; public: Trie(const unordered_set words) : root(make_unique()) { for (const string& w : words) { insert(w); } } bool find(const string& prefix) const { const unique_ptr *current = &root; for (char c : prefix) { if ((*current)->children[c-'a'] != nullptr) { current = &(*current)->children[c-'a']; } else { return false; } } return true; } void insert(const string& word) { unique_ptr *current = &root; for (char c : word) { if ((*current)->children[c-'a'] != nullptr) { current = &(*current)->children[c-'a']; } else { (*current)->children[c-'a'] = make_unique(); current = &(*current)->children[c-'a']; } } } }; class Rectangle { vector rectangle; int cols; const vector>& dict; const Trie& prefixes; public: long words_count = 0; Rectangle(size_t rows, size_t cols, const Trie& prefixes, const vector>& dict) : rectangle(rows), cols(cols), dict(dict), prefixes(prefixes) { } const vector& get() const { return rectangle; } bool check_feasible(int upto_rows) { string prefix; prefix.reserve(upto_rows); for (int col = 0; col < cols; col++) { // Check each column if it is a valid prefix. for (int row = 0; row <= upto_rows; row++) prefix.push_back(rectangle[row][col]); if (!prefixes.find(prefix)) return false; prefix.resize(0); } return true; } bool build_rectangle(int rows_left) { if (rows_left == 0) return true; size_t n = rectangle.size() - rows_left; for (const string& w : dict[cols]) { // Fill nth row with word, check feasibility, and continue. rectangle[n] = w; words_count++; if (check_feasible(n)) { bool ok = build_rectangle(rows_left-1); if (ok) return true; continue; } } return false; } }; int main(void) { unordered_set dict = read_dictionary("words.txt"); vector> by_len = by_length(dict); vector ra; int longest = by_len.size()-1; long words_count = 0; for (int cols = longest; cols > 0; cols--) { Trie t(by_len[cols]); for (int rows = longest; rows > 1; rows--) { Rectangle r(rows, cols, t, by_len); if (r.build_rectangle(rows)) { ra = r.get(); words_count += r.words_count; goto out; } words_count += r.words_count; } } out: if (ra.size() > 0) { cout << "found rectangle!\n"; for (size_t i = 0; i < ra.size(); i++) { cout << ra[i] << "\n"; } } cout << "Searched " << words_count << " words\n"; return 0; }