代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<string.h>//这个库和cstring一样,而且是兼容。
using namespace std;
struct que
{
char s[30];
int ti;
}q1[5010],q2[5010];//要开两个队列,一个从头到尾,一个从尾到头。
char a[7][30],b[7][30];
int n,head1,tail1,head2,tail2;
bool check(char *s1,char *s2)//判断此次扩展后,两个队列中字符串是否相等。
{
if (strlen(s1)!=strlen(s2)) return 0;
for (int i=0;i<strlen(s1);i++)
if (s1[i]!=s2[i]) return 0;
return 1;
}
bool rep1(char *s,int i,int x)
{
for (int j=i;j<i+strlen(a[x]);j++)//此处a[x]代表二维字符中的一行字符串。
if (s[j]!=a[x][j-i]) return 0;
return 1;
}
bool rep2(char *s,int i,int x)
{
for (int j=i;j<i+strlen(b[x]);j++)
if (s[j]!=b[x][j-i]) return 0;
return 1;
}
void bfs()
{
int head1,tail1,head2,tail2,k;
head1=tail1=head2=tail2=1;
while (head1<=tail1 && head2<=tail2)//用两个队列,双向bfs。
{
if (q1[head1].ti+q2[head2].ti>10)//判断边界,双向的话,每个扩展和超过10个就不行了.
{
printf("NO ANSWER!\n");
return;
}
for(int i=0;i<strlen(q1[head1].s);i++)
for (int j=1;j<=n;j++)//一个一个往后扩展,每次替换一下,寻找最优。
if (rep1(q1[head1].s,i,j))
{
tail1++;
for(k=0;k<i;k++) q1[tail1].s[k]=q1[head1].s[k];
for(int t=0;t<strlen(b[j]);t++,k++) q1[tail1].s[k]=b[j][t];
for(int t=i+strlen(a[j]);t<=strlen(q1[head1].s);t++,k++) q1[tail1].s[k]=q1[head1].s[t];
q1[tail1].s[k]='\0';
q1[tail1].ti=q1[head1].ti+1;
for (k=1;k<=tail2;k++)
if (check(q1[tail1].s,q2[k].s))//每次扩展后,都与另一个队列比较,下同。
{
printf("%d\n",q1[tail1].ti+q2[k].ti);
return ;
}
}
for(int i=0;i<strlen(q2[head2].s);i++)
for(int j=1;j<=n;j++)
if (rep2(q2[head2].s,i,j))
{
tail2++;
for(k=0;k<i;k++) q2[tail2].s[k]=q2[head2].s[k];
for(int t=0;t<strlen(a[j]);t++,k++) q2[tail2].s[k]=a[j][t];
for(int t=i+strlen(b[j]);t<=strlen(q2[head2].s);t++,k++) q2[tail2].s[k]=q2[head2].s[t];
q2[tail2].s[k]='\0';
q2[tail2].ti=q2[head2].ti+1;
for(k=1;k<=tail1;k++)
if (check(q1[k].s,q2[tail2].s))
{
printf("%d\n",q1[k].ti+q2[tail2].ti);
return ;
}
}
head1++,head2++;
}
printf("NO ANSWER!\n");
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
ios::sync_with_stdio(false);
scanf("%s%s",q1[1].s,q2[1].s);
n=1;
head1=head2=tail1=tail2=1;
while (scanf("%s%s",a[n],b[n])!=EOF) n++;//EOF为文件判断结束,该方法仅限文件输入。
n--;
q1[1].ti=q2[1].ti=0;//起始。
bfs();
fclose(stdin);
fclose(stdout);
return 0;
}
按照一般的思路,一定是一次一次枚举了,每次操作一下,再看看跟结果是否一样,很普通的bfs,但是,请思考一下这几个问题:如果当前字符串中有多个可被替换的子字符串?或者是问你应该替换哪一个?这道题需要大量的字符串操作,如find,size等,而这些操作的效率是很低的,虽然数据量不大,但它不会超时么?
貌似一般的方法无法解决刚才的两个问题。
先看第一个问题:其实这个问题很简单,如果当前字符串里有多个子被替换字符串,那么只要每次都取当前字符串的后length-i个字符再看看头几个字符是不是我们想要的不就好了!这样也省去了每次找被替换字符串的时间,可以提高很多效率。
对于第二个问题:我并不是很确定我是对的,find等函数效率低,那我们是不是可以自己写一个替换的函数或者是语句呢?我建议写c语言的字符串,效率比c++的要高一些,多写点是不错,但是这是很省时的一种办法。
好了,如果解决了上面的问题,是否能把这道题A掉我不知道,也没有试过,不过,这道题的精妙之处仍然没有体现,说了那么多字符串了,现在就说一说这王中王的bfs吧!
这道题有一个特点:起始和终止都是已知的,只是要求次数。而广搜又是一层一层扩展的,所以,我们为什么不从起点和终点同时扩展,每次都判断一下他们所扩展的有没有重合的,如果有,就输出结果,总次数就是两个bfs的次数和,这倒是让我想到了小学语文课文中詹天佑修铁路时的两端同时开进的方法,大大节省了工作的时间,提高了工作的效率,而这种从起点和终点两个反方向的bfs,就叫做——双向广度优先搜索。
如果以上的所以问题都写到了,那这道题就可以无压力的秒过了,个人认为,这种方法,只要知道他的核心思想以及大致写法就好了,平常的题目中这种题应该是比较少见的,关键在于思维的养成,比赛中如果能想到这种思路,它叫什么双向广度优先搜索又怎么样呢?
好了,总结也写完了,我只是个初学c++不到一年的菜鸟,各路大神多多指点。