题目描述
已知有两个字串A,B及一组字串变换的规则(至多6个规则):
A1->B1
A2-> B2
规则的含义为:在A中的子串A1可以变换为B1,A2可以变换为 B2…。
例如:A=abcd,B=xyz,
变换规则为:
abc→xu,ud→y,y→yz
则此时,A可以经过一系列的变换变为B,其变换的过程为:
abcd→xud→xy→xyz。
共进行了3次变换,使得A变换为B。
输入格式
输入格式如下:
A B
A1 B1
A2 B2 |-> 变换规则
... ... /
所有字符串长度的上限为20。
输出格式
输出至屏幕。格式如下:
若在10步(包含10步)以内能将A变换为B,则输出最少的变换步数;否则输出"NO ANSWER!"
思路:BFS
输入时用f数组记录变换规则,并记录种数。枚举每一种变换规则,因为在同一字符串A中可能有很多重复的A1所处的位置不同,所以要用while,同时将处理过的位置打标记。使用hash判重。本题容易想到BFS但对于字符串的处理是难点,所以专门用了两个函数处理变换过程。
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N=231,M=400009;
char a[N],b[N],s1[N],s2[N],f[10][3][N],q[M][N];
int tot,ans[M],Hash[M];
void init()
{
scanf("%s %s",a,b);
while (scanf("%s %s",s1,s2)!=EOF)
{
strcpy(f[++tot][1],s1);
strcpy(f[tot][2],s2);
}
}
void delete1(char s[],int sum,int len)
{
int j=sum;
for (int i=sum+len; i<strlen(s); i++)
{
s[j]=s[i]; j++;
}
s[j]='\0';
}
void join(char s[],char st[],int sum)
{
char a1[N],a2[N],j=0;
for (int i=0; i<sum; i++) a1[i]=s[i];
a1[sum]='\0';
for (int i=sum; i<strlen(s); i++)
{
a2[j]=s[i]; j++;
}
a2[j]='\0';
strcpy(s,a1); strcat(s,st); strcat(s,a2);
}
int Hashh(char s[])
{
long long res=0;
int i=0;
while (i<strlen(s))
{
res+=res*131+s[i];
res=(res&0x07FFFFFF);
i++;
}
return res%M;
}
void bfs()
{
int l=0,r=1,sum;
strcpy(q[1],a); ans[1]=0;
while (l<r&&ans[l+1]<=10)
{
l++;
for (int i=1; i<=tot; i++)
{
strcpy(s1,q[l]);
sum=strstr(s1,f[i][1])-s1;
while (strstr(s1,f[i][1])!=NULL)
{
strcpy(s2,q[l]);
delete1(s2,sum,strlen(f[i][1]));
join(s2,f[i][2],sum);
int k=Hashh(s2);
if (Hash[k]!=0)
{
s1[sum]=' ';
sum=strstr(s1,f[i][1])-s1;
continue;
}
Hash[k]=1;
r++; strcpy(q[r],s2); ans[r]=ans[l]+1;
if (strcmp(s2,b)==0)
{
printf("%d\n",ans[r]);
return;
}
s1[sum]=' ';
sum=strstr(s1,f[i][1])-s1;
}
}
}
printf("No Solution!\n");
}
int main()
{
init();
bfs();
return 0;
}