洛谷 P1032 字串变换
题目描述
已知有两个字串A,BA,B及一组字串变换的规则(至多66个规则):
A1 -> B1
A2 -> B2
规则的含义为:在 A中的子串 A1可以变换为 B1 ,A2可以变换为B2 …。
例如:A=‘abcd’BB=’xyz’
变换规则为:
‘abc’->‘xu’ ‘ud’->‘y’ ‘y’->‘yz’
则此时,A可以经过一系列的变换变为B,其变换的过程为:
‘abcd’->‘xud’->‘xy’->‘xyz’
共进行了3次变换,使得A变换为B。
输入输出格式
输入格式:
输入格式如下:
A B
A1 B1
A2 B2 |-> 变换规则
… … /
所有字符串长度的上限为2020。
输出格式:
输出至屏幕。格式如下:
若在10步(包含10步)以内能将A变换为B,则输出最少的变换步数;否则输出"NO ANSWER!"
最短路用bfs…
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n=0,ans=-1;
char c[6][25],d[6][25];
char a[40],b[40];
struct T{
int l;
char s[40];
}q[10000005];//按我这种方法数组要够大才行 TAT
int find(int s,char x[],char y[])//从s开始在x中找y
{
int lx=strlen(x),ly=strlen(y);
if(lx-s<ly)
return -1;
int flag;
for(int i=s;i<=lx-ly;++i)
{
if(x[i]==y[0])
{
flag=1;
int j=1;
while(j<ly)
{
if(x[i+j]!=y[j])
{
flag=-1;
break;
}
j++;
}
if(flag==1)
return i;
}
}
return -1;
}
void del(char x[],char y[],int s,int l)//y变成x,然后从s开始删l个
{
int xx=strlen(x);
memset(y,'\0',sizeof(y));
memcpy(y,x,xx);
int i=0;
while(s+i+l<xx)
{
y[s+i]=y[s+i+l];
i++;
}
if(y[xx-l]!='\0')
y[xx-l]='\0';
}
void trans(char x[],char y[],int s)//在x里从s开始插入y
{
int ly=strlen(y);
int lx=strlen(x);
for(int i=lx+ly-1;i>s;--i)
{
x[i]=x[i-ly];
}
if(x[lx+ly]!='\0')
x[lx+ly]='\0';
for(int i=s;i<s+ly;++i)//不能=s+ly
{
x[i]=y[i-s];
}
}
int equal(char x[],char y[])//判等
{
int lx=strlen(x),ly=strlen(y);
if(lx!=ly)
return -1;
for(int i=0;i<lx;++i)
if(x[i]!=y[i])
return -1;
return 1;
}
void bfs()
{
int h=0,t=1;
int x,l;
q[1].l=0;
x=strlen(a);
for(int i=0;i<x;++i)
q[1].s[i]=a[i];
do{
h++;
for(int i=0;i<n;++i)
{
if(q[h].l>=10)//剪枝,不剪可能出不去...
break;
x=-1;
l=strlen(c[i]);
while(1)//可能含有多个
{
x=find(x+1,q[h].s,c[i]);
if(x==-1)
break;
t++;
del(q[h].s,q[t].s,x,l);
trans(q[t].s,d[i],x);
q[t].l=q[h].l+1;
if(equal(q[t].s,b)==1)
{
ans=q[t].l;
return;
}
}
}
}while(h<t);
}
int main(){
cin>>a>>b;
while(cin>>c[n]>>d[n])
n++;
bfs();
if(ans==-1)
printf("NO ANSWER!\n");
else
printf("%d\n",ans);
return 0;
}