<?xml version="1.0" encoding="windows-1252"?>
<node id="558342" title="A Better Word Morph Builder" created="2006-06-29 11:30:02" updated="2006-06-29 07:30:02">
<type id="115">
perlquestion</type>
<author id="180961">
Limbic~Region</author>
<data>
<field name="doctext">
All,
&lt;br /&gt;
In [id://558123|this thread], [Ieronim] posted a cool script.  It finds the shortest bridge between two words where all the words in the bridge can be found in &lt;i&gt;a dictionary&lt;/i&gt; and each word differs from its adjacent partners by only one character.
&lt;p&gt;
I posted what I believe to be a very fast elegant solution:
&lt;READMORE&gt;
&lt;CODE&gt;
#!/usr/bin/perl
use strict;
use warnings;
use Storable;

my ($src, $tgt) = @ARGV;
die "Usage: $0 &lt;src&gt; &lt;tgt&gt;" if ! defined $src || ! defined $tgt;
die "The &lt;src&gt; and &lt;tgt&gt; must be same length" if length($src) != length($tgt);

my $db = retrieve('dictionary.db');
my $path = find_path($src, $tgt, $db-&gt;{length($tgt)});
print "$path\n";

sub find_path {
    my ($src, $tgt, $list, $seen, $work) = @_;
    @$work = map {key =&gt; $_ =&gt; path =&gt; "$src-&gt;$_"}, @{$list-&gt;{$src}} if ! defined $work;
    my $next = [];    
    for (@$work) {
        my ($word, $path) = @{$_}{qw/key path/};
        next if $seen-&gt;{$word}++;
        return $path if $word eq $tgt;
        push @$next, map {key =&gt; $_, path =&gt; "$path-&gt;$_"}, @{$list-&gt;{$word}};
    }
    return find_path($src, $tgt, $list, $seen, $next) if @$next;
    return 'path not found';
}
&lt;/CODE&gt;
&lt;/READMORE&gt;
&lt;/p&gt;
&lt;p&gt;
The algorithm is simple.  First, create a datastructure that relates all words of a given length to all other words of the same length with a [wp://Levenshtein Distance] of 1.  This is a one time up-front cost.  Next, simply perform a [wp://Breadth-first_search|breadth first search] starting from one end and stopping when the other end is encountered.
&lt;/p&gt;
&lt;p&gt;
With the hard work done up front, the task can be accomplished in about 20 lines of code.  Is anyone aware of  a more efficient (faster run-time) algorithm?  As usual, this is just one of my "I want to learn" questions and there is no real-world speed barrier I am trying to break.  It just seemed to me that there should be some way to eliminate some paths during the BFS.  I think an evolutionary algorithm technique might work.  Paths that increase the Levenshtein Distance to the target word would not be allowed to survive.  Even if this does work, I am not sure that the reduction in search space is worth the added distance calculation.
&lt;/p&gt;
&lt;p&gt;
I appreciate any ideas on this.
&lt;/p&gt;
&lt;small&gt;
&lt;small&gt;
* The original did allow for the endpoints not to be dictionary words.
&lt;/small&gt;
&lt;/small&gt;
&lt;div class="pmsig"&gt;&lt;div class="pmsig-180961"&gt;
&lt;p&gt;
Cheers - [Limbic~Region|L~R]
&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;</field>
</data>
</node>
