洛谷 P1032 字串变换
题目
题目描述
已知有两个字串 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’
共进行了三次变换,使得 A 变换为B。
输入输出格式
输入格式:
键盘输人文件名。文件格式如下:
A B A1 B1 \
A2 B2 |-> 变换规则
… … /
所有字符串长度的上限为 20。
输出格式:
输出至屏幕。格式如下:
若在 10 步(包含 10步)以内能将 A 变换为 B ,则输出最少的变换步数;否则输出”NO ANSWER!”
输入输出样例
输入样例#1:
abcd xyz
abc xu
ud y
y yz
输出样例#1:
3
题解
双向BFS
代码(Pascal)
var a:array[0..1,0..10005]of string;
q:array[0..1,0..100005]of string;
tt:array[0..1,0..10005]of longint;
head,tail:array[0..1]of longint;
bs,t,s1,s2,s:string;
n:longint;
procedure rec(s:string);
var k:longint;
begin
k:=pos(' ',s);
s1:=copy(s,1,k-1);
s2:=copy(s,k+1,length(s)-k);
end;
procedure init;
begin
readln(s);rec(s);
bs:=s1;t:=s2;n:=0;
while not eof do
begin
readln(s);
if s='' then exit;
inc(n);
rec(s);
a[0,n]:=s1;a[1,n]:=s2;
end;
end;
function vis(s:string;t:longint):boolean;
var i:longint;
begin
vis:=false;
for i:=1 to tail[t] do
if q[t,i]=s then exit(true);
end;
procedure check(t:longint);
var i:longint;
begin
for i:=1 to tail[1-t] do
if q[1-t,i]=q[t,tail[t]] then
begin
writeln(tt[1-t,i]+tt[t,tail[t]]);
halt;
end;
end;
procedure bfs(t:longint);
var i,j,k:longint;
pre,tmp:string;
begin
inc(head[t]);
pre:=q[t,head[t]];
for i:=1 to n do
begin
k:=length(a[t,i]);
for j:=1 to length(pre)-k+1 do
begin
if copy(pre,j,k)=a[t,i] then
begin
tmp:=copy(pre,1,j-1)+a[1-t,i]+copy(pre,j+k,length(pre)-j-k+1);
if not vis(tmp,t) then
begin
inc(tail[t]);
q[t,tail[t]]:=tmp;
tt[t,tail[t]]:=tt[t,head[t]]+1;
end;
check(t);
end;
end;
end;
end;
procedure main;
begin
head[0]:=0;tail[0]:=1;
head[1]:=0;tail[1]:=1;
q[0,1]:=bs;tt[0,1]:=0;
q[1,1]:=t;tt[1,1]:=0;
while (head[0]<tail[0])and(head[1]<tail[1])do
if tail[1]<tail[0] then bfs(1) else bfs(0);
end;
procedure print;
begin
writeln('NO ANSWER!');
end;
begin
init;
main;
print;
end.