Algoritmer og datastrukturer Kapittel 11 - Delkapittel 11.2



Like dokumenter
Algoritmer og datastrukturer Kapittel 9 - Delkapittel 9.2

Algoritmer og datastrukturer Eksamen

TOD063 Datastrukturer og algoritmer

G høgskolen i oslo. Emne: Algoritmer og datastrukturer. Emnekode: 80131A. Faglig veileder: UlfUttersrud. Gruppe(r) : Dato:

Algoritmer og datastrukturer Kapittel 11 Delkapittel 11.2

OPPGAVE 5b og 8b Java Kode

Repetisjon. INF gruppe 13

HØGSKOLEN I SØR-TRØNDELAG Avdeling for informatikk og e-læring - AITeL

Algoritmer og datastrukturer Eksamen

Algoritmer og datastrukturer Kapittel 9 - Delkapittel 9.1

UNIVERSITETET I OSLO

import java.io.*; import java.util.*; import javagently.text;

HØGSKOLEN I SØR-TRØNDELAG

Eksamen i emnet INF100 Grunnkurs i programmering (Programmering I) Løsningsforslag

LITT OM OPPLEGGET. INF1000 EKSTRATILBUD Stoff fra uke September 2012 Siri Moe Jensen EKSEMPLER

Algoritmer og datastrukturer Løsningsforslag

EKSAMEN. Algoritmer og datastrukturer. Eksamensoppgaven: Oppgavesettet består av 11 sider inklusiv vedlegg og denne forsiden.

Litt om pakker og mest om data inn og ut

Oppgave 3 a. Antagelser i oppgaveteksten. INF1020 Algoritmer og datastrukturer. Oppgave 3. Eksempelgraf

Løsningsforslag Test 2

Algoritmer og datastrukturer Kapittel 1 - Delkapittel 1.3

INF Løsning på seminaropppgaver til uke 8

Løsningsforslag ukeoppg. 9: okt (INF Høst 2011)

Løsnings forslag i java In115, Våren 1996

Algoritmer og datastrukturer Kapittel 5 - Delkapittel 5.4

Algoritmer og datastrukturer Kapittel 1 - Delkapittel 1.8

HØGSKOLEN I SØR-TRØNDELAG Avdeling for informatikk og e-læring AITeL

Norges Informasjonsteknologiske Høgskole

Universitetet i Bergen Det matematisk-naturvitenskapelige fakultet Institutt for informatikk

Algoritmer og datastrukturer Kapittel 3 - Delkapittel 3.1

Kapittel 14, Hashing. Tema. Definere hashing Studere ulike hashfunksjoner Studere kollisjonsproblemet 17-1

NITH PG4200 Algoritmer og datastrukturer Løsningsforslag Eksamen 4.juni 2013

Introduksjon til objektorientert. programmering. Hva skjedde ~1967? Lokale (og globale) helter. Grunnkurs i objektorientert.

Socket og ServerSocket

Oppgave 1. Sekvenser (20%)

Algoritmer og Datastrukturer

Algoritmer og datastrukturer Kapittel 4 - Delkapittel 4.3

Algoritmer og datastrukturer Eksamen 22. februar 2011

Hva er verdien til variabelen j etter at følgende kode er utført? int i, j; i = 5; j = 10; while ( i < j ) { i = i + 2; j = j - 1; }

Algoritmer og datastrukturer Løsningsforslag

Løsningsforslag. Oppgave 1.1. Oppgave 1.2

Oblig 4 (av 4) INF1000, høsten 2012 Værdata, leveres innen 9. nov. kl

Forkurs INF1010. Dag 3. Andreas Færøvig Olsen Eivind Storm Aarnæs

Ordliste. Obligatorisk oppgave 1 - Inf 1020

INF1010 våren 2019 Onsdag 30. januar. Mer om unntak i Java (med litt repetisjon av I/O først)

Løsningsforslag, inf101, våren 2001

UNIVERSITETET I OSLO

Eksamen i emnet INF100 Grunnkurs i programmering (Programmering I) og i emnet INF100-F Objektorientert programmering i Java I Løsningsforslag

Algoritmer og datastrukturer Eksamen

UNIVERSITETET I OSLO

"Nelsons kaffebutikk"

EKSAMEN med løsningsforslag

Tre måter å lese fra terminal. Java 4. Eksempel. Formatert utskrift til skjerm

Korteste vei i en vektet graf uten negative kanter

Algoritmer og datastrukturer Løsningsforslag

Løse reelle problemer

Løsnings forslag i java In115, Våren 1998

Oppgave 1 LØSNINGSFORSLAG. Eksamen i INF desember Betrakt følgende vektede, urettede graf:

INF1010, 22. mai Prøveeksamen (Eksamen 12. juni 2012) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

INF1010 LISTER. Listeelementer og listeoperasjoner. Foran. Bak

INF1010. grensesni-et Comparable<T> grensesni-et Iterable<T> rekursjon

Løsningsforslag EKSAMEN

INF1010, 21. februar Om å gå gjennom egne beholdere (iteratorer) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

~ta11 oppgaver: 4. Nle skriftlige hjelpemidler-både trykte og håndskrevne, er tillatt

MED TIDESTIMATER Løsningsforslag

Algoritmer og datastrukturer Eksamen

Oppgave 1. Løsningsforslag til eksamensoppgave. ITF20006 Algoritmer og datastrukturer Postorden traversering:

EKSAMEN. Dato: 18. mai 2017 Eksamenstid: 09:00 13:00

Algoritmer og datastrukturer Løsningsforslag

Oppgave 1 a. INF1020 Algoritmer og datastrukturer. Oppgave 1 b

UNIVERSITETET I OSLO

Anvendelser av grafer

NORGES INFORMASJONSTEKNOLOGISKE HØGSKOLE PG4200 Algoritmer og datastrukturer

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

Løsningsforslag til INF110 h2001

3 emner i dag! INF1000 Uke 5. Objekter og pekere. null. Litt om objekter, pekere og null Filer og easyio Litt mer om tekster

INF110 Algoritmer og datastrukturer TRÆR. Vi skal i denne forelesningen se litt på ulike typer trær:

Algoritmer og datastrukturer Kapittel 5 - Delkapittel 5.1

UNIVERSITETET I BERGEN Det matematisk-naturvitenskapelige fakultet

UNIVERSITETET I OSLO

Kapittel 9: Sortering og søking Kort versjon

IN2010: Algoritmer og Datastrukturer Series 2

Ny/utsatt EKSAMEN. Dato: 6. januar 2017 Eksamenstid: 09:00 13:00

Transkript:

Algoritmer og datastrukturer Kapittel 11 - Delkapittel 11.2 11.2 Korteste vei i en graf 11.2.1 Dijkstras metode En graf er et system med noder og kanter mellom noder. Grafen kalles rettet Notasjon Verdien til en node X skrives som v(x) og lengden på kanten fra node X til node Y (avstanden fra X til Y) skrives k(x,y). Algoritmens start Velg en node som startnode, farg noden gul og gi den verdien 0. Farg de nodene som er direkte etterfølgere til startnoden røde og gi dem som verdier den avstanden de har fra startnoden. Resten av nodene skal være grå og skal ikke ha noen verdier foreløpig. 1. Hvis det ikke er noen røde noder igjen, så er vi ferdige. Hvis det er røde noder igjen, velg den blant de røde som har minst verdi. Hvis det er flere med samme minste verdi, så spiller det ingen rolle hvem av dem en velger. Kall den valgte noden X. 2. De direkte etterfølgerne til X er enten farget grå, røde eller gule. De som er grå skal farges røde og får som verdier summen av verdien til X og avstandene fra X til nodene (vektene/lengdene på kantene fra X til nodene). F.eks. hvis en grå direkte etterfølger til X heter Y, så skal verdien til Y (v(y)) bli lik v(x) + k(x,y). Hvis en direkte etterfølger til X er rød, så skal den beholde sin farge. Den har, siden den er rød, allerede fått en verdi. La Z være en rød direkte etterfølger til X. Hvis v(x) + k(x,z) er mindre enn v(z), så skal Z få v(x) + k(x,z) som ny verdi! Hvis v(x) + k(x,z) ikke er mindre enn v(z), så skal Z beholde sin gamle verdi. Hvis en direkte etterfølger til X er gul, så skal den ikke endres verken i farge eller verdi. 3. Farg noden X gul og gå så tilbake til 1. Du kan nå sjekke forståelsen din ved å titte på en applett med Dijkstras algoritme. Den bruker fargene omtrent som beskrevet over. Den eneste forskjellen er at startnoden blir farget blå. 11.2.2 Implementasjon av Dijkstras metode I implementasjonen av Dijkstras metode bruker vi en prioritetskø. Nodene farges røde i det øyeblikket de legges inn i prioriteskøen. Kantene og nodene er som definert i underkapittel 11.1.2. Grafens noder ligger i en nodetabell og alle kantene ut fra en node er kjedet sammen. Se underkapittel 11.1.2. import java.util.*; import java.io.*; /////////////////////////// /// /// /// CLASS GRAF /// /// /// /////////////////////////// Side 1 av 14

Side 2 av 14 public class Graf // private konstanter private final int TABDIM = 64; private final int NULLNODE = -1; private final int UENDELIG = Integer.MAX_VALUE/3; //////////////////// // class Kant ////// //////////////////// private static class Kant // Edge private int til; // noden kanten går til private int lengde; // kantens lengde private Kant neste; // peker til neste kant // konstruktør public Kant(int til, int lengde, Kant neste) this.til = til; this.lengde = lengde; this.neste = neste; //////////////////// // class Node ////// //////////////////// private static class Node // Vertex private String nodenavn; // nodens navn private Kant førstekant; // peker til første kant i kantlisten private int avstand; // avstand hit private int forrige; // foregående node i korteste vei hit private int teller; // hjelpevariabel // konstruktør public Node (String nodenavn) this.nodenavn = nodenavn; førstekant = null; // en tabell av noder private Node[] node; // En avbildning (map) holder orden på hvilke noder (nodenavn) // grafen består og hvilke nummer nodene er tildelt private Map h; private int antallnoder; // antall noder i gafen

Side 3 av 14 /////////////////////////////////////// // PRIVATE HJELPEMETODER /////////////////////////////////////// // privat hjelpemetode private void utvidtabell() Node[] temp = node; node = new Node[2*antallNoder]; // dobler System.arraycopy(temp,0,node,0,antallNoder); // privat hjelpemetode private void nullstill() Node p = null; for (int i = 0; i < antallnoder; i++) p = node[i]; p.avstand = UENDELIG; p.forrige = NULLNODE; p.teller = 0; // en rekursiv hjelpemetode som bruker teknikken "dybde først" // den kalles fra en off. metode med samme navn - se nedenfor private void kortestvei1(int fra, int lengdehit) Kant k = node[fra].førstekant; if (lengdehit + k.lengde < node[k.til].avstand) node[k.til].avstand = lengdehit + k.lengde; node[k.til].forrige = fra; kortestvei1(k.til,lengdehit + k.lengde); ////////////////////////////////////////////// /// OFFENTLIGE METODER ////////////////////////////////////////////// public Graf() // konstruktør node = new Node[TABDIM]; // nodetabellen h = new HashMap(); // holder orden på nodene antallnoder = 0; // i utgangspunktet 0 noder

Side 4 av 14 /// nynode ////////////////////////////// public boolean nynode(string nodenavn) Object o = h.get(nodenavn); // Er navn registrert tidligere? if (o!= null) return false; // duplikater ikke tillatt h.put(nodenavn,new Integer(antallNoder)); // Før vi legger noden i nodetabellen må vi sjekke om den // er full! Hvis ja, så utvider vi tabellen! if (antallnoder == node.length) utvidtabell(); // utvider node[antallnoder++] = new Node(nodenavn); // ny node return true; // ny node lagt inn ///// nykant ////////////////////////////////// // Offentlig metode som legger inn nye kanter i grafen public boolean nykant(string fra, String til, int lengde) Object o = h.get(fra); if (o == null) return false; // ingen node med dette navnet int franode = ((Integer)o).intValue(); o = h.get(til); if (o == null) return false; // ingen node med dette navnet int tilnode = ((Integer)o).intValue(); Kant k = node[franode].førstekant; if (k.til == tilnode) // vi oppaterer lengden på en eksistrende kant k.lengde = lengde; return true; // dette er ingen kant mellom disse nodene fra før node[franode].førstekant = new Kant(tilnode,lengde,node[franode].førsteKant); return true; /// skrivgraf ///////////////////////////////////7

Side 5 av 14 // en metode som skriver ut for hver node hvilke andre noder // det går en kant til. public void skrivgraf(string fil) throws IOException PrintWriter ut = new PrintWriter(new FileWriter(fil)); Kant k = null; for (int i = 0; i < antallnoder; i++) ut.print("kanter fra " + node[i].nodenavn + " til: "); k = node[i].førstekant; if (k == null) ut.print(" ingen kanter ut fra denne noden"); else ut.print(node[k.til].nodenavn + " (len. " + k.lengde + ") "); ut.println(); ut.close(); /// skrivvei /////////////////////////////////////// // Skriver korteste vei fra en startnode til tilnode. // Utskriften går til ut public void skrivvei(string til, PrintWriter ut) Object o = h.get(til); if (o == null) return; // ukjent navn Stakk s = new TabellStakk(); int nodenr = ((Integer)o).intValue(); int avstand = node[nodenr].avstand; if (avstand == UENDELIG) ut.println("det er ingen vei til " + node[nodenr].nodenavn); while (nodenr!= NULLNODE) s.legginn(new Integer(nodenr)); nodenr = node[nodenr].forrige; while (!s.tom()) ut.print(((integer)(s.taut())).intvalue() + " - ");

Side 6 av 14 ut.println(" lengde = " + avstand); ////////////////////////////////////////////// /// OFFENTLIGE METODER ////////////////////////////////////////////// public Graf() // konstruktør node = new Node[TABDIM]; // nodetabellen h = new HashMap(); // holder orden på nodene antallnoder = 0; // i utgangspunktet 0 noder /// nynode ////////////////////////////// public boolean nynode(string nodenavn) Object o = h.get(nodenavn); // Er navn registrert tidligere? if (o!= null) return false; // duplikater ikke tillatt h.put(nodenavn,new Integer(antallNoder)); // Før vi legger noden i nodetabellen må vi sjekke om den // er full! Hvis ja, så utvider vi tabellen! if (antallnoder == node.length) utvidtabell(); // utvider node[antallnoder++] = new Node(nodenavn); // ny node return true; // ny node lagt inn ///// nykant ////////////////////////////////// // Offentlig metode som legger inn nye kanter i grafen public boolean nykant(string fra, String til, int lengde) Object o = h.get(fra); if (o == null) return false; // ingen node med dette navnet int franode = ((Integer)o).intValue(); o = h.get(til); if (o == null) return false; // ingen node med dette navnet int tilnode = ((Integer)o).intValue(); Kant k = node[franode].førstekant; if (k.til == tilnode) // vi oppaterer lengden på en eksistrende kant k.lengde = lengde; return true;

Side 7 av 14 // dette er ingen kant mellom disse nodene fra før node[franode].førstekant = new Kant(tilnode,lengde,node[franode].førsteKant); return true; /// skrivgraf ///////////////////////////////////7 // en metode som skriver ut for hver node hvilke andre noder // det går en kant til. public void skrivgraf(string fil) throws IOException PrintWriter ut = new PrintWriter(new FileWriter(fil)); Kant k = null; for (int i = 0; i < antallnoder; i++) ut.print("kanter fra " + node[i].nodenavn + " til: "); k = node[i].førstekant; if (k == null) ut.print(" ingen kanter ut fra denne noden"); else ut.print(node[k.til].nodenavn + " (len. " + k.lengde + ") "); ut.println(); ut.close(); /// skrivvei /////////////////////////////////////// // Skriver korteste vei fra en startnode til tilnode. // Utskriften går til ut public void skrivvei(string til, PrintWriter ut) Object o = h.get(til); if (o == null) return; // ukjent navn Stakk s = new TabellStakk(); int nodenr = ((Integer)o).intValue(); int avstand = node[nodenr].avstand; if (avstand == UENDELIG)

Side 8 av 14 ut.println("det er ingen vei til " + node[nodenr].nodenavn); while (nodenr!= NULLNODE) s.legginn(new Integer(nodenr)); nodenr = node[nodenr].forrige; while (!s.tom()) ut.print(((integer)(s.taut())).intvalue() + " - "); ut.println(" lengde = " + avstand); /// graffrafil /////////////////////////////////////// // en metode som leser en fil med grafdata og bygger opp // grafen. Filen må være organisert på en bestemt måte void graffrafil(string filnavn) throws IOException BufferedReader inn = new BufferedReader(new FileReader(filnavn)); StringTokenizer str = null; String tekst = inn.readline(); int antall = Integer.parseInt(tekst); int antkanter = 0; String fra = null; String til = null; for (int i = 0; i < antall; i++) str = new StringTokenizer(inn.readLine()); fra = str.nexttoken(); nynode(fra); antkanter = Integer.parseInt(str.nextToken()); for (int j = 0; j < antkanter; j++) til = str.nexttoken(); nynode(til); nykant(fra,til,integer.parseint(str.nexttoken())); /// Dijkstra ////////////////////////////////////////// // en metode som bruker Dijkstras algoritme for korteste vei public void Dijkstra(String franode) // en lokal hjelpeklasse class Avstand

Side 9 av 14 int nodenr; int avstand; Avstand(int nodenr, int avstand) this.nodenr = nodenr; this.avstand = avstand; // en lokal komparator for class Avstand class AvstandKomparator implements Comparator public int compare(object a, Object b) return ((Avstand)b).avstand - ((Avstand)a).avstand; Object o = h.get(franode); // sjekker om noden eksisterer if (o == null) return; // ukjent navn nullstill(); PrioritetsKø q = new HeapPrioritetsKø(new AvstandKomparator()); Kant k = null; // hjelpevariabel Node denne = null; // hjelpevariabel Node etterfølger = null; final int GRÅ = 0; final int GUL = 1; final int RØD = 2; int nodenr = ((Integer)o).intValue(); denne = node[nodenr]; // startnoden denne.avstand = 0; denne.teller = RØD; q.legginn(new Avstand(nodenr,0)); while (!q.tom()) nodenr = ((Avstand)q.taUt()).nodenr; denne = node[nodenr]; if (denne.teller!= RØD) continue; // hopper over denne k = denne.førstekant; int tempavstand = 0; // hjelpevariabel

Side 10 av 14 tempavstand = denne.avstand + k.lengde; etterfølger = node[k.til]; if (tempavstand < etterfølger.avstand) etterfølger.avstand = tempavstand; etterfølger.forrige = nodenr; etterfølger.teller = RØD; q.legginn(new Avstand(k.til,tempavstand)); // denne.teller = GUL; // ferdig med denne // while (!q.tom()) // Dijkstra /// kortestevei1 - rekursiv dybde først /////////// public void kortestvei1(string franode) // denne metoden kaller opp en rekursiv hjelpemetode // - se ovenfor Object o = h.get(franode); if (o == null) return; // ukjent nodenavn nullstill(); int nodenr = ((Integer)o).intValue(); node[nodenr].avstand = 0; kortestvei1(nodenr,0); /// kortestevei2 /////////////////////////////////// // en metode som ved hjelp av en stakk bruker "dybde først" public void kortestvei2(string franode) Object o = h.get(franode); if (o == null) return; // ukjent nodenavn nullstill(); Stakk s = new TabellStakk(); int nodex = ((Integer)o).intValue(); int nodey; // hjelpevariabel node[nodex].avstand = 0; node[nodex].teller = 1; // 1 betyr på stakk s.legginn(o);

Side 11 av 14 Kant k; try while (!s.tom()) nodex = ((Integer)(s.taUt())).intValue(); node[nodex].teller = 0; // 0 betyr ikke på stakk k = node[nodex].førstekant; nodey = k.til; if (node[nodex].avstand + k.lengde < node[nodey].avstand) node[nodey].avstand = node[nodex].avstand + k.lengde; node[nodey].forrige = nodex; if (node[nodey].teller == 0) // 0 betyr ikke på stakk s.legginn(new Integer(nodeY)); node[nodey].teller = 1; // 1 betyr på stakk catch (TomStakk t) /// kortestevei3 ///////////////////////////////////// // en metode som ved hjelp av en kø bruker "bredde først" public void kortestvei3(string franode) Object o = h.get(franode); if (o == null) return; // ukjent navn nullstill(); Kø q = new TabellKø(); int nodex = ((Integer)o).intValue(); int nodey; node[nodex].avstand = 0; node[nodex].teller = 1; // 1 betyr på kø q.legginn(o); Kant k;

Side 12 av 14 while (!q.tom()) nodex = ((Integer)(q.taUt())).intValue(); node[nodex].teller = 0; // 0 betyr ikke på kø k = node[nodex].førstekant; nodey = k.til; if (node[nodex].avstand + k.lengde < node[nodey].avstand) node[nodey].avstand = node[nodex].avstand + k.lengde; node[nodey].forrige = nodex; if (node[nodey].teller == 0) // 0 betyr ikke på kø q.legginn(new Integer(nodeY)); node[nodey].teller = 1; // 1 betyr på kø /// kortestuvektetvei ///////////////////////////////// // En metode som bruker "bredde først" for å finne korteste // vei når vi antar at alle kantene har samme lengde public void kortestuvektetvei(string fra) Object o = h.get(fra); if (o == null) return; // ukjent navn nullstill(); Kø q = new TabellKø(); int nodenr = ((Integer)o).intValue(); Node franode = node[nodenr]; franode.avstand = 0; q.legginn(new Integer(nodenr)); Kant k; Node tilnode; while (!q.tom()) nodenr = ((Integer)(q.taUt())).intValue();

Side 13 av 14 franode = node[nodenr]; k = franode.førstekant; tilnode = node[k.til]; if (tilnode.avstand == UENDELIG) tilnode.avstand = franode.avstand + 1; tilnode.forrige = nodenr; // nodenr er nr. til franode q.legginn(new Integer(k.til)); /// asykliskkortestvei /////////////////////////// // En metode som bruker "toplogisk sortering" for å finne // korteste vei i en graf som ikke har sykler public boolean asykliskkortestvei(string fra) Object o = h.get(fra); if (o == null) return false; // ukjent navn nullstill(); Kø q = new TabellKø(); Kant k; // hjelpevariabel int nodenr = ((Integer)o).intValue(); node[nodenr].avstand = 0; // avstand i startnode settes til 0 // variablen teller i hver node skal settes til antallet // inngående kanter til noden for (nodenr = 0; nodenr < antallnoder; nodenr++) k = node[nodenr].førstekant; while(k!= null) node[k.til].teller++; // noder som ikke har inngående kanter legges i køen - det må // finnes minst en slik node siden grafen ikke har sykler

Side 14 av 14 for (nodenr = 0; nodenr < antallnoder; nodenr++) if (node[nodenr].teller == 0) q.legginn(new Integer(nodenr)); // hovedløkken starter int i; for (i = 0;!q.tom(); i++) nodenr = ((Integer)(q.taUt())).intValue(); k = node[nodenr].førstekant; if (--node[k.til].teller == 0) q.legginn(new Integer(k.til)); // vi behandler kun noder som har vært "besøkt" - i // begynnelsen er det bare startnoden som har vært "besøkt" if (node[nodenr].avstand < UENDELIG) if (node[k.til].avstand > node[nodenr].avstand + k.lengde) node[k.til].avstand = node[nodenr].avstand + k.lengde; node[k.til].forrige = nodenr; return i == antallnoder; // slutt på class Graf