题目
总时间限制: 1000ms 内存限制: 1024kB
描述
给出两个单词(开始单词和结束单词)以及一个词典。找出从开始单词转换到结束单词,所需要的最短转换序列。转换的规则如下:
1、每次只能改变一个字母
2、转换过程中出现的单词(除开始单词和结束单词)必须存在于词典中
例如:
开始单词为:hit
结束单词为:cog
词典为:[hot,dot,dog,lot,log,mot]
那么一种可能的最短变换是: hit -> hot -> dot -> dog -> cog,
所以返回的结果是序列的长度5;
注意:
1、如果不能找到这种变换,则输出0;
2、词典中所有单词长度一样;
3、所有的单词都由小写字母构成;
4、开始单词和结束单词可以不在词典中。
输入
共两行,第一行为开始单词和结束单词(两个单词不同),以空格分开。第二行为若干的单词(各不相同),以空格分隔开来,表示词典。单词长度不超过5,单词个数不超过30。
输出
输出转换序列的长度。
样例输入
hit cog
hot dot dog lot log
样例输出
5
分析
一看数据比较小,暴力搜索即可。dfs和bfs都可以。
代码实现
#include <set>
#include <string>
#include <iostream>
#include<stack>
#pragma warning(disable: 4996) //make Visual Studio happy
#define MAXLEN 5
#define MAXNUM 30
#define INF 0x7FFFFFFF
using std::set;
using std::string;
using std::cin;
using std::cout;
int wordLen;
set<char> possibleChars[MAXLEN];
string beg, end;
set<string> dictionary;
void Input()
{
char buf[MAXLEN + 1];
cin >> beg >> end;
wordLen = beg.length();
cin.get();
string s;
do {
cin >> s;
dictionary.insert(s);
for (int i = 0; i < wordLen; i++)
possibleChars[i].insert(s[i]);
} while (cin.get() == ' ');
for (int i = 0; i < wordLen; i++)
{
possibleChars[i].insert(beg[i]);
possibleChars[i].insert(end[i]);
}
}
// dfs
int MinDistToEnd(const string& s)
{
if (s == end) return 0;
int minDist = INF;
for(int i = 0; i < wordLen; i++)
for (char ch : possibleChars[i]) if (ch != s[i]) {
string s_ = s;
s_[i] = ch;
if (s_ == end)
minDist = 1; // 更换后,即得到结束串
else if (dictionary.find(s_) == dictionary.end()) // 更换后,不在字典内
continue;
else { //更换后在字典内
dictionary.erase(s_); // 字典中移除s_,避免它被再次搜索到
int dist = MinDistToEnd(s_);
dist = dist == INF ? INF : dist + 1;
minDist = dist < minDist ? dist : minDist;
dictionary.insert(s_); // 恢复s_在字典中
}
}
return minDist;
}
int main()
{
Input();
int dist = MinDistToEnd(beg);
if (dist == INF) cout << 0;
else cout << dist + 1;
return 0;
}