P1032
写这道不算难的题目是我遇到了不少问题,复述以下过程吧。
由于数据很水,这道题用不到KMP算法,只要使用朴素算法进行字符串比对就可以了。
1
首先,我错误的选择了dfs算法,导致了TLE的发生。这类求最优解的问题显然大多应该用bfs解决,可是改用bfs后依然不对。
2
过了一天,我我发现自己忘了考虑如果一个字符串多处都可以用同一规则替换,那么各处替换都应该考虑到的这一问题。最开始我都是只替换第一处的。后来意识到这一问题是我刚开始觉得如果每一处都有换和不换两种情况且有n处可换的话,我岂不是应该把2的n次方个元素插入队列?这样实现起来好麻烦,又不如深搜了。后来我意识到我并不需要插入2
的n次方个元素,我只需要插入n个就可以了,即分别是“第一处改其他都不改”、“第二处改其他都不改”、...、等等。因为那种”“第xy处改”的情况其实当只有第x处改的那个入队的元素出队的时候自然会考虑到,所以并不需要现在考虑那个问题。于是我解决了这一问题再然后,我发现依然TLE了,观看题解发现bfs竟然也要排重才可以,否则哪怕是bfs算法,不排重也会算的贼慢。排重自然是想到用了map,然而,使用map后五个点中有两个点RE,剩下三个点AC。我在本地ide中测试发现终端输出libc++abi: terminating due to uncaught exception of type std::out_of_range: basic_string,意思是抛出了一个out_of_range异常。我把map有关的查重代码注释掉之后就不在异常了,说明是查重代码if (m.find(tstr.s) != m.end()) {continue;}m[tstr.s]=1;导致了out_of_range异常的抛出,可我不理解为何如此已经该怎么修
3
过了一天,我出去玩了,又过了一天,我重新开始想这道题,我发现事实并非如我昨天想的那样,删除map有关代码就不再报错并不一定是因为map抛出了异常
,还有可能是map导致的代码执行的变化致使其他函数抛出了异常,自己之前的那个把罪直接定在map上的想法实在是太绝对了。事实上,是string抛出了异常,原因也很简单,我访问了越界的数据。在strf::can这个“判断s能否使用Vi规则进行替换”的函数时忘了Vi(a->b)规则的a有可能比s还长。我先入为主的认为了s应该是一个长串,导致了没想到这个问题。后来我使用输出中间变量的办法好久也没发现问题所在,直到用调试模式开始逐步调试的时候才发现了问题所在,然后加入了一行简单的判断代码就解决了这个问题。
教训
1、要慎重选用bfs还是dfs,最优解问题应该选用dfs,涉及输入过程的bfs和dfs都可以做到过程输出,更应该看需要输出一个过程还是所有过程,从而判断是bfs还是dfs。
2、别舍不得排重用到的空间,很多时候排重能带来很大的时间优化。
3、不能武断的判断抛出异常的对象。
4、涉及字符串和数组的每个部分都一定要考虑好是否越界。
5、应当更习惯使用调试程序来排错而非输出中间数据来排错。
最终代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <stack>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
using namespace std;
struct strf
{
string a,b;
strf(string x,string y){a=x;b=y;}
int can(string s,int pass)
{
if(s.length()<a.length()) return -1;
for(int i=0;i<=s.length()-a.length();i++)
{
int flag=1;
for(int j=i;j<=i+a.length()-1;j++)
{
if(s[j]!=a[j-i])
{
flag=0;
break;
}
}
if(flag==1)
{
if(pass==0)
return i;
else
pass--;
}
}
return -1;
}
string doit(string s,int pos)
{
string tail=s.substr(pos+a.length());
s.erase(pos,s.length()-pos); s+=b; s+=tail;
return s;
}
};
struct str{string s;int step;str(string S,int Step){s=S;step=Step;}};
vector<strf> V;//其实可以换成链表来存储,在这个特定需求下,很适合用链表
string A,B,s1,s2;
queue<str> q;
map<string,int> m;
int main()
{
cin>>A>>B;
while(cin>>s1>>s2)
V.push_back(strf(s1,s2));
q.push(str(A,0));
while(!q.empty())
{
str tstr(q.front()); q.pop();
if(tstr.step>10)break;
if(tstr.s==B){cout<<tstr.step<<endl;return 0;}
if (m.find(tstr.s) != m.end()) {continue;} m[tstr.s]=1;
for(int i=0;i<V.size();i++)
for(int pass=0;V[i].can(tstr.s,pass)!=-1;pass++)
q.push(str(V[i].doit(tstr.s,V[i].can(tstr.s,pass)),tstr.step+1));
}
cout<<"NO ANSWER!"<<endl;
return 0;
}