原题链接:https://www.luogu.org/problem/show?pid=1032#sub
很奇怪,莫名其妙就A掉了。。。真神奇2333
洛谷红名留念。我会继续努力。
题意已经把做法写得特别露骨了。。。最小步数,最多6个变换规则。。。。广搜自不必说,不仅可以寻找解而且还能判断步数(根据广搜首解最优的性质可以得到)。
开两个数组记录串的转换关系,然后以a串(原串)为起点开始搜索,搜索目标是b串。
需要一个map记录某个串是不是被搜到过,如果已经搜过了就不再继续搜 。
我们枚举当前队列中队头那个串的每一个位置,对每一个位置枚举所有可能的转换手段,然后去尝试拼接。
拼接函数借鉴了一下楼上stdcall大爷题解的思路,对于一个试图要改变的串str,我们试图在它的第i位用第j种手段改变,首先判断是否可行,然后再逐位拼接。并且如果拼接出的串是合法的,那么我们就把这个串继续压入队列,再次搜索,中间记录一下步数step和ans。
最后输出ans时判断,如果ans超过了步数限制直接输出无解,否则输出步数。
不过我发现,ans等于0时应该也是无解,这样会导致如果用ans<=10来判断是不是超出步数会WA掉第三个点。。
参考代码:
1 #include <iostream> 2 #include <string> 3 #include <cstring> 4 #include <queue> 5 #include <map> 6 #define maxn 15 7 using namespace std; 8 struct node{//方便搜索,也可以使用pair简化 9 string str; 10 int step; 11 }; 12 13 string a,b; 14 string orginal[maxn]; 15 string translated[maxn]; 16 int n,ans; 17 map<string,int> ma;//很重要的东西,用来判重,否则会TLE在第3点和第5点 18 19 string trans(const string &str,int i,int j){//借鉴了stdcall大爷的思想 20 string ans = ""; 21 if (i+orginal[j].length() > str.length()) 22 return ans; 23 24 for (int k=0; k < orginal[j].length();k++) 25 if (str[i+k] != orginal[j][k]) 26 return ans; 27 28 ans = str.substr(0,i); 29 ans+=translated[j]; 30 ans+=str.substr(i+orginal[j].length()); 31 return ans; 32 } 33 34 void bfs(){//一个平淡无奇的bfs过程 35 queue <node> q; 36 node s; 37 s.str = a; 38 s.step = 0; 39 q.push(s); 40 41 while (!q.empty()){ 42 node u = q.front(); 43 q.pop(); 44 string temp; 45 46 if(ma.count(u.str) == 1) //剪枝,判断重复的路径 47 continue; 48 49 if (u.str == b){ 50 ans = u.step; 51 break; 52 } 53 ma[u.str] = 1; 54 for (int i=0;i < u.str.length();i++)//枚举当前串所有可能位置 55 for (int j=0; j<n; j++){//枚举所有可能手段 56 temp = trans(u.str,i,j); 57 if (temp != ""){ 58 node v; 59 v.str = temp; 60 v.step = u.step+1; 61 q.push(v); 62 } 63 } 64 } 65 if (ans > 10 || ans == 0) 66 cout << "NO ANSWER!" << endl; 67 else 68 cout << ans << endl; 69 70 } 71 72 int main(){ 73 cin >> a >> b; 74 while (cin >> orginal[n] >> translated[n]) 75 n++; 76 bfs(); 77 return 0; 78 }