hst 11.3

advertisement
Hoofdstuk 11.3
Algoritmen:
Zoeken in een
netwerk
Routeplanner
Spoorwegkaart:
Klik startpunt
Klik eindpunt
eind
start
Programma
bepaalt route
Klik nieuw
startpunt...
start
Modellering
elk traject heeft “kosten”;
route met laagste totaalprijs
is de beste
Zoek de “beste” route
Opbouw van het netwerk
staat in een file, met:
voor elke stad: naam en coördinaten
voor elke weg: 2 steden, en de kosten
stad Amersfoort
330 350
stad Amsterdam
250 310
stad Apeldoorn
420 330
weg Amersfoort Apeldoorn
weg Amsterdam Hilversum
weg Hilversum Amersfoort
43
29
16
Specificatie
 Bij eerste muisklik: en 3e, 5e, 7e...
aangewezen stad is het beginpunt
toon die in blauw
 Bij tweede muisklik: en 4e, 6e, 8e...
aangewezen stad is eindpunt
bereken de route, en toon die in rood
 Bij klik buiten een stad:
telt niet mee
Opdeling in klassen
Interactieve interface met EventHandler voor:
class RouteZoeker : Form
teken
klik
Belangrijke object-typen
class
class
class
class
Stad
Weg
Pad
Netwerk
met in elke klasse:
een constructor-methode
een methode Teken
om zichzelf te tekenen
...
Klasse-ontwerp
wat is ...
membervariabelen
wat kan ...
een object
methodeheaders
en hoe ?
methodebodies
De klasse RouteZoeker
class RouterZoeker : Form
{
Netwerk netwerk;
de “blauwe” stad
Stad stad1;
of null
Pad pad;
Button b;
TextBox t;
Label lab;
“het” netwerk
het “rode” pad
of null
we tekenen
alles zelf!
Event-handlers
void klik(..., MouseEventArgs mea) { ...... }
void teken(..., PaintEventArgs pea) { ...... }
De klasse Netwerk
class Netwerk
{
Stad [ ] Steden;
alle steden
op de kaart
ICollection<Stad> Steden;
ICollection<Weg> Wegen;
we gaan per stad
alle uitgaande
wegen bewaren
De klasse Stad
class Stad
{
string Naam;
Point Plek;
ICollection<Weg> Wegen;
Utrecht
De klasse Weg
class Weg
{
Stad Doel;
int Kosten;
De klasse Pad
class Pad
{
IList<Stad> Steden;
Stad Hier;
Pad Rest;
int Kosten;
ongeveer een
LinkedList,
maar dan
zelfgemaakt
null
Methoden van Stad
class Stad
{
String Naam;
Point Plek;
ICollection<Weg> wegen; static Font font = new ...
Stad ( String s, Point p )
{
Naam = s; Plek = p;
Wegen = new LinkedList<Weg> ( );
}
void Teken (Graphics gr, Brush br)
{
gr . FillRectangle(br
Utrecht
, Plek.X-5, Plek.Y-5, 10, 10 );
gr . DrawString (Naam, font, br
, Plek + new Size(6,-15) );
}
Methoden van Weg
class Weg
{
Stad Doel; int Kosten;
Weg ( Stad s, int k )
{
Doel =s; Kosten = k;
}
wordt niet
getekend
void Teken (Graphics gr, Pen pen ) , Stad bron )
{
gr . DrawLine ( pen, bron.Plek, Doel.Plek );
}
Methoden van Pad
class Pad
{ Stad Hier; Pad Rest; int Kosten;
totale kosten
van het pad
Pad ( Stad s, Pad r, int k )
{
Hier = s; Rest = r; Kosten = k;
if (Rest != null) Kosten += Rest.Kosten;
}
void Teken (Graphics gr, Brush br, Pen pen)
Hier . Teken (gr, br);
{
if (Rest != null)
{ gr.DrawLine( pen, Hier.Plek, Rest.Hier.Plek );
Rest . Teken (gr, br, pen);
}
}
Methoden van Netwerk
class Netwerk
{
ICollection<Stad> Steden;
Netwerk ( )
{
Steden = new LinkedList<Stad> ( );
}
void Teken (Graphics gr)
{
foreach ( Stad stad in Steden )
{
stad . Teken (gr, Brushes.Black);
foreach ( Weg w in stad.wegen )
w.Teken (gr, Pens.Black, stad)
}
}
bron
Methoden van RouteZoeker
class RouteZoeker
{
Netwerk netwerk; Stad stad1; Pad pad;
init ( )
{
netwerk = new Netwerk(); stad1=null; pad=null;
}
void teken (object o, PaintEventArgs pea)
{ Graphics gr = pea.Graphics;
netwerk . teken (gr);
if (pad != null)
pad . teken(gr, Brushes.Red, Pens.Red);
if (stad1 != null) stad1 . teken(gr, Brushes.Blue);
}
Opbouw van het Netwerk
Lees een file met regels zoals:
commando
stad Almelo
520 280
stad Amersfoort
330 350
stad Amsterdam
250 310
stad Apeldoorn
420 330
stad Arnhem
410 380
weg Arnhem
Zutphen
weg Zutphen
Deventer
weg Deventer Zwolle
weg Amsterdam Weesp
weg Weesp
Hilversum
weg Hilversum Amersfoort
locatie
29
16
31
14
15
16
kosten
Opbouw van het Netwerk
void Lees (string filenaam )
StreamReader sr = new StreamReader(filenaam);
{
while ( (regel=sr.ReadLine()) != null )
{
string [] r = regel.Split(" ", StringSplitOptions.RemoveEmpty );
if (r.Length==4)
if (r[0] == "stad")
{
this . bouwStad (r[1]
new Point( int.Parse(r[2])
, int.Parse(r[3]) ) );
}
else
{ this.bouwWeg( r[1], r[2], int.Parse(r[3]) );
}
}
}
Opbouw van het Netwerk
void bouwStad (string naam, Point p)
{
Stad st = new Stad(naam, p);
Steden . Add (st);
Netwerk’s
}
void bouwWeg (string van, string naar, int kosten)
{ Stad st1 = this . vindStad (van);
Stad st2 = this . vindStad (naar);
}
st1 . BouwWeg (st2, kosten); class Stad {
st2 . BouwWeg (st1, kosten); void BouwWeg(Stad doel, int k)
{ Wegen . Add (
Stad’s
}
new Weg(doel, k) );
Opbouw van het Netwerk
Stad vindStad (String naam)
{
}
foreach ( Stad st in Steden )
{
if ( st.naam == naam )
return st ;
}
return null ;
Stad VindStad (Point p)
{
foreach ( Stad st in steden )
{
Math.abs( p.X-st.Plek.X < 5 )
if (
&& Math.abs( p.Y-st.Plek.Y <5 )
return st ;
}
return null ;
)
Interactie in RouteZoeker
class RouteZoeker : Form
{
Netwerk netwerk;
Stad stad1;
Pad pad;
void klik (..., MouseEventArgs mea)
{
Stad s = netwerk . VindStad( mea.Location );
if ( s != null )
eerste klik { if (stad1==null) stad1 = s;
of
else { pad = netwerk . ZoekPad (stad1, s );
tweede klik?
stad1 = null;
}
this . Invalidate ();
}
}
Het zoek-algoritme
maak een stapel van
nog-niet-complete,
maar veelbelovende
paden
Pad ZoekPad
(Stad begin, Stad eind)
{
Stack<Pad> paden
= new Stack<Pad>();
Het zoeken begint...
Pad pad;
pad = new Pad(begin, null, 0);
null
paden . push (pad);
hij is niet
groot...
null
0
maar wel
veelbelovend!
Onderzoek paden uit stapel...
while ( paden.Count > 0 )
{
Pad pad = paden . pop();
if (pad.Hier==eind)
return pad;
foreach ( Weg weg in pad . Hier . Wegen )
{
beter = new Pad( weg.Doel, pad, weg.Kosten);
paden . Push(beter);
}
}
return null;
Pas op:
niet in een
kringetje zoeken!
één van de
wegen kom je
net vandaan!
foreach ( Weg weg in pad.Hier.Wegen )
{
if ( ! pad . Bevat (weg.Doel) )
{
beter = new Pad( weg.Doel, pad, weg.Kosten);
paden . Push(beter);
}
}
Niet de eerste oplossing,
maar de beste zoeken!
while ( ... )
{ pad = ...
if (compleet)
return pad;
for (...)
if ( !kring )
paden.Push(...)
}
return null;
beste = null;
while ( ... )
{ pad = ...
if (compleet)
if (beter)
beste=pad;
beste=pad;
return
pad;
for (...)
if ( !kring )&& !zinloos)
paden.Push(...)
}
return
return null;
beste;
Uitwerking
Wat is “beter” ?
if ( beste==null
|| pad.Kosten < beste.Kosten
) beste = pad;
Wat is “niet zinloos” ?
if ( beste==null
|| pad.Kosten + weg.Kosten < beste.Kosten
) paden.Push (new Pad (...) );
Verbetering van het algoritme
De meest veelbelovende
eerst onderzoeken
ordenen qua
afstand tot doel
Dus in volgorde van
afstand tot naar pushen
moet een
lComparer zijn
wegen = new SortedSet<Weg>( pad.Hier.Wegen , naar );
class Stad : IComparer<Weg> {
{ int Compare( Weg a, Weg b)
{ return this.afstand(b.doel) – this.afstand(a.doel);
}
Routezoeker compleet!
Download