题目:SmartWordToy
思路:4个字母的单词有26 ^ 4种组合,可以看成是26 ^ 4种状态,用BFS搜索最短步骤。
代码如下:
/* * TopCoder: SmartWordToy (http://community.topcoder.com/stat?c=problem_statement&pm=3935&rd=6532) * Author: xuzhezhao * E-mail: zhezhaoxu@gmail.com * Time: 2013/6/1 */ #include <iostream> #include <queue> #include <string> #define WORDS (26 * 26 * 26 * 26) /* 单词总的组合数 */ using namespace std; class SmartWordToy { public: int minPresses(string start, string finish, string forbid[]); }; /* 单词状态结构 */ typedef struct { string word; /* 单词 */ int steps; /* 到达此状态的步骤数 */ }Button; bool isForbid(string test, string forbid[]); char nextChar(char ch); char preChar(char ch); int getWordIndex(string word); bool visited[WORDS]; /* 单词是否被访问的标志 */ int main() { SmartWordToy toy; string start = "aaaa"; string finish = "zzzz"; string forbid[] = {""}; /* 初始化visited数组 */ for (int i = 0; i < WORDS; i++) { visited[i] = false; } cout << toy.minPresses(start, finish, forbid) << endl; return 0; } int SmartWordToy::minPresses(string start, string finish, string forbid[]) { queue <Button> Q; Button button, button_temp; if (isForbid(finish, forbid)) { return -1; } button.word = start; button.steps = 0; Q.push(button); while (button.word != finish && !Q.empty()) { button = Q.front(); Q.pop(); /* 每次都有4个按键可以选择,每个按键可以选择向上或向下按 */ for (int i = 0; i < 4; i++) { /* 向上按 */ button_temp = button; button_temp.word[i] = nextChar(button_temp.word[i]); if (!visited[getWordIndex(button_temp.word)]) { visited[getWordIndex(button_temp.word)] = true; ++button_temp.steps; if (!isForbid(button_temp.word, forbid)) { Q.push(button_temp); } } /* 向下按 */ button_temp = button; button_temp.word[i] = preChar(button_temp.word[i]); if (!visited[getWordIndex(button_temp.word)]) { visited[getWordIndex(button_temp.word)] = true; ++button_temp.steps; if (!isForbid(button_temp.word, forbid)) { Q.push(button_temp); } } } } if (button.word != finish) { return -1; } else { return button.steps; } } /** * 判断test字符串是否是满足forbid条件的字符串, * 是返回true,否则返回false. */ bool isForbid(string test, string forbid[]) { int i; int len; /* length of forbid */ int pos1, pos2, pos3; /* white space positons */ string s0, s1, s2, s3; len = 0; while ("" != forbid[len]) { ++len; } /* 当forbid数组为空时,返回false */ if (0 == len) { return false; } for (i = 0; i < len; i++) { pos1 = forbid[i].find_first_of(' ', 0); pos2 = forbid[i].find_first_of(' ', pos1 + 1); pos3 = forbid[i].find_first_of(' ', pos2 + 1); s0 = forbid[i].substr(0, pos1); s1 = forbid[i].substr(pos1 + 1, pos2 - pos1 - 1); s2 = forbid[i].substr(pos2 + 1, pos3 - pos2 - 1); s3 = forbid[i].substr(pos3 + 1, forbid[i].length() - pos3 - 1); /* 如果是forbid字符串,则返回true */ if (string::npos != s0.find_first_of(test[0], 0) && string::npos != s1.find_first_of(test[1], 0) && string::npos != s2.find_first_of(test[2], 0) && string::npos != s3.find_first_of(test[3], 0)) { return true; } } /* 不是forbid字符串 */ return false; } /** * 返回在字母表中ch的下一个字符,字母表为循环的,即z的下一个字符为a */ char nextChar(char ch) { if ('z' == ch) { ch = 'a'; } else { ++ch; } return ch; } /** * 返回在字母表中ch的上一个字符,字母表为循环的,即a的上一个字符为z */ char preChar(char ch) { if ('a' == ch) { ch = 'z'; } else { --ch; } return ch; } /** * 返回每个单词的索引,将每个单词看成26进制数,a - z 分别表示 0 - 25, * 单词的数值就是索引值。 */ int getWordIndex(string word) { return ((word[0] - 'a') * (26 * 26 * 26) + (word[1] - 'a') * (26 * 26) + (word[2] - 'a') * 26 + (word[3] - 'a') ); }