题面
给出最多6个 str1->str2
的变换规则,问能否在10次以内将给出的串1变为串2。如能,则输出最少变换次数
字符串长度不超过20
分析
从最少变换次数这里不难想到bfs,结合find查找串中是否有 str1
的可变换串,再用 string的replace方法可以直接得到变换后的串
坑点1:find只会找到一个 str1 并对其做变换,但实际上变换发生的位置可以是多个的,所以每一个节点可到达的状态不止变换规则数量那么多。
例如原串 aaab 在规则 a->c
中通过一次操作可以得到三种串:caab
, acab
, aacb
.这些都要统计入
为了应对这种情况,用 find(string, start_pos)的方法,找到所有 str1
存在的位置即可
p = cur.find(rules[0][i], p + 1);//相当于迭代
坑点2:坑点1会带来大量可能性,不是一秒内能处理的,并且会有很多重复。
所以剪枝,策略是发现对每一个串,都要检查所有的替换规则,所以在不同位置出现的同一个串可到达的情况是相同的,于是舍弃操作次数较多才能出现的该串,只保留第一次(bfs序保证这个串操作次数要小于等于其他相同的串)。这可用hash来完成,这里用map来实现hash,发现已经出现过,则跳过。
代码
#include <stdio.h>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<map>
using namespace std;
int flag = -1;//记录答案
int num = 0;
string ans;
string rules[2][7];
queue<pair<string,int> >q;
map<string, int>m;
void bfs(string str)
{
q.push(make_pair(str,0));
int deep,p=0;
string cur;
string temp;
while (!q.empty())
{
cur = q.front().first;
deep = q.front().second;
q.pop();
if (cur == ans) { flag = deep;break; }
if (m.count(cur)==1||deep == 10)continue;//m.count即hash去重
m[cur] = 1;
for (int i = 0; i < num; i++)
{
p=cur.find(rules[0][i]);
while (p!=cur.npos)
{
temp = cur;
q.push(make_pair(temp.replace(p, rules[0][i].length(), rules[1][i]), deep + 1));
p = cur.find(rules[0][i], p + 1);//迭代寻找所有可能替换
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
string raw;
cin >> raw >> ans;
while (cin>>rules[0][num])
{
cin >> rules[1][num++];
}
bfs(raw);
if (flag != -1)cout << flag;
else cout << "NO ANSWER!";
return 0;
}