/* * Prof. Sloan model solution to Program 5b, CS 202, Nov. 2002 */ #include #include #include #include #include "Graph.hh" using namespace std; bool offByOne(const string& w1, const string& w2); int main (int argc, char* argv[]) { const string defaultDictionary = "/usr/dict/words"; const string noPathMessage = "IMPOSSIBLE"; string word; // where dictionary words go Graph wordGraph; // graph with words on nodes string begin = argv[1]; string end = argv[2]; if (argc != 4) { cout << argv[0] << ": usage is " << argv[0] << " word1 word2 dict-file" << endl; return 0; } int wordLength = begin.size(); if (end.size() != wordLength) { cout << "puz: words must have same length" << endl; return 1; } ifstream dictionary(argv[3]); cout << "Building graph on words of length " << wordLength << ". . . ." << endl; do { dictionary >> word; if (word.size() == wordLength) { wordGraph.insertVertex(word); // cout << word; } } while (dictionary); if (!(wordGraph.containsVertex(begin) && wordGraph.containsVertex(end))) { cerr << "puz: One or both input words not in Dictionary." << endl; return 1; } Graph::iterator i, j; // to walk through & insert edges for (i = wordGraph.begin(); i != wordGraph.end(); i++) for (j = wordGraph.begin(); j != wordGraph.end(); j++) if (i != j && offByOne(*i, *j) ) wordGraph.insertEdge( *i, *j); cout << "Searching graph for transformation. . . ." << endl; list wordList; Graph::dfs_reach_iterator itr; for (itr = wordGraph.dfs_reach_begin(begin); itr != wordGraph.dfs_reach_end(); itr++) { wordList.push_back(*itr); if ((*itr) == end) break; } if (itr == wordGraph.dfs_reach_end()) { cout << noPathMessage << endl; return 0; } // cout << "Transformation possible. Long list is" << endl; // list::iterator debugItr; // for (debugItr = wordList.begin(); debugItr != wordList.end(); // ++debugItr) // cout << *debugItr << " "; // cout << endl; cout << endl << "Now constructing output. . . ." << endl; // Prune dfsList to get simple path list::iterator listItrFront = wordList.begin(); list::iterator listItrBack = --wordList.end(); list::iterator listItrPenultimate; list::iterator listItrWalk; while (1) { listItrPenultimate = listItrBack; --listItrPenultimate; // Now points to 2nd last if (listItrFront == listItrPenultimate || listItrFront == listItrBack) break; listItrWalk = listItrBack; while (! wordGraph.containsEdge(*listItrFront, *listItrWalk)) --listItrWalk; // walk back till edge from Front->Walk cout << "Found edge (" << *listItrFront << ", " << *listItrWalk << ")" << endl; if ( ++listItrFront != listItrWalk) // some can be cut out! listItrFront = wordList.erase(listItrFront, listItrWalk); } for (listItrWalk = wordList.begin(); listItrWalk != wordList.end(); listItrWalk++) cout << *listItrWalk << endl; return 0; } //Returns true if and only if w1 and w2 are of same length and //different by exactly one char bool offByOne(const string& w1, const string& w2) { if (w1.size() != w2.size()) return false; int numDifferent = 0; for (int i = 0; i < w1.size(); i++) if (w1[i] != w2[i]) ++numDifferent; return (numDifferent == 1); }