예제 #1
0
 /// <summary>
 /// Gibt das Ergebnis in der vorgegebenen Form in einem StreamWriter aus
 /// </summary>
 /// <remarks>
 /// Historie:  23.05.2012  (awi) Erstellt
 /// </remarks>
 /// <param name="sw">Ein StreamWriter zur Ausgabe</param>
 /// <param name="e">Ein Ergebnis Objekt</param>
 private void ErgebnisAusgabe(StreamWriter sw, Ergebnis e)
 {
     if (sw != null)
     {
         sw.WriteLine(e.sKommentar);
         sw.WriteLine("Startzelle: {0}, {1}, Zielzelle: {2}, {3}", e.si + 1, e.sk + 1, e.zi + 1, e.zk + 1);
         sw.WriteLine("Abschätzung der Kostenobergrenze: {0} KE", e.iKostenAbsch);
         sw.WriteLine("Minimalkosten: {0} KE", e.iKostenMinimal);
         sw.Write("Weg: ");
         for (int iKnoten = 0; iKnoten < e.kuerzesterWeg.GetLength(0); iKnoten++)
         {
             if (iKnoten == 0)
             {
                 sw.Write("S; ");
             }
             else if (iKnoten == e.kuerzesterWeg.GetLength(0) - 1)
             {
                 sw.Write("Z\n");
             }
             else
             {
                 sw.Write("{0},", e.ZeileZuKnoten(e.kuerzesterWeg[iKnoten]) + 1);
                 sw.Write("{0}; ", e.SpalteZuKnoten(e.kuerzesterWeg[iKnoten]) + 1);
             }
         }
     }
 }
예제 #2
0
        /// <summary>
        /// Gibt eine Adjazenzmatrix des Ergebnis Objekts auf dem Bildschirm zu Testzwecken aus
        /// Hinweise:  Unendlich wird als INF (infinity) dargestellt
        /// Historie:  22.05.2012  (awi) Erstellt
        /// </summary>
        /// <param name="e">Ein Ergebnis Objekt</param>
        public void AdjazenzMatrixAusgabe(Ergebnis e)
        {
            String s;

            // über alle Zeilen
            for (int i = 0; i < e.AdjazenzMatrix.GetLength(0); i++)
            {
                s = ""; // String für die Zeilenweise Ausgabe
                // über alle Spalten
                for (int k = 0; k < e.AdjazenzMatrix.GetLength(1); k++)
                {
                    if (e.AdjazenzMatrix[i, k] == Konstante.UNENDLICH)
                    {
                        // Unendlich wird als INF (infinity) ausgegeben
                        s = s + "INF , ";
                    }
                    else
                    {
                        // Wert ausgeben
                        s = s + String.Format("{0,3}", e.AdjazenzMatrix[i, k]) + " , ";
                    }
                }
                Console.WriteLine(s);
            }
        }
예제 #3
0
        /// <summary>
        /// Gibt das Ergebnis in der vorgegebenen Form in einer Datei aus
        /// </summary>
        /// <remarks>
        /// Historie:  22.05.2012  (awi) Erstellt
        ///            23.05.2012  (awi) Ausgabe in gesonderte Methode gekapselt
        /// </remarks>
        /// <param name="sDateiname">Ein String mit einem Dateinamen</param>
        /// <param name="e">Ein Ergebnis Objekt</param>
        public void ErgebnisDateiAusgabe(String sDateiname, Ergebnis e)
        {
            // Datei als SW öffnen
            StreamWriter sw;

            try
            {
                sw = new StreamWriter(sDateiname, false, Encoding.UTF8);
            }
            catch
            {
                throw new FieldAccessException("Datei (" + sDateiname + ") konnte nicht zum Schreiben geöffnet werden.");
            }

            try
            {
                ErgebnisAusgabe(sw, e);
            }
            catch
            {
                Console.WriteLine("Ergebnis konnte nicht in Datei (" + sDateiname + ") geschrieben werden.");
            }

            sw.Close();
        }
예제 #4
0
        /// <summary>
        /// Gibt das Ergebnis in der vorgegebenen Form auf dem Bildschirm aus
        /// </summary>
        /// <remarks>
        /// Historie:  22.05.2012  (awi) Erstellt
        ///            23.05.2012  (awi) Ausgabe in gesonderte Methode gekapselt
        /// </remarks>
        /// <param name="e">Ein Ergebnis Objekt</param>
        public void ErgebnisAusgabe(Ergebnis e)
        {
            // Console als SW übergeben
            StreamWriter sw = new StreamWriter(Console.OpenStandardOutput(), Console.OutputEncoding);

            sw.AutoFlush = true;
            ErgebnisAusgabe(sw, e);
            sw.Close();
        }
예제 #5
0
        /// <summary>
        /// Errechnet eine Kostenabschätzung
        /// </summary>
        /// <remarks>
        /// Hinweise:  -  errechnet eine triviale Lösung des Problems.
        ///               Läuft im eingelesenen Feld zunächst vom Start auf
        ///               die Höhe des Ziels und von dort zum Ziel.
        ///               Die summierten Kosten dieses Weges ist die
        ///               Kostenabschätzung
        ///            -  Feld im Ergebnis Objekt muss bereits angelegt sein
        /// Historie:  22.05.2012  (awi) Erstellt
        /// </remarks>
        /// <param name="e">Ein Ergebnis Objekt</param>
        static void KostenAbsch(Ergebnis e)
        {
            int iKosten = 0;
            int iIterator;

            if (e.Feld == null)
            {
                throw new Exception("Feld im Ergebnis Objekt nicht angelegt");
            }

            //vertikale Richtung
            if (e.si < e.zi)
            {
                // Ziel liegt "unterhalb" von Start
                iIterator = 1;
            }
            else
            {
                // Ziel liegt "oberhalb" von Start
                iIterator = -1;
            }

            // Weg gehen und Kosten summieren
            for (int i = e.si; i != e.zi; i = i + iIterator)
            {
                iKosten += e.Feld[i, e.sk];
            }

            //horizontale Richtung
            if (e.sk < e.zk)
            {
                // Ziel liegt "rechts" von Start
                iIterator = 1;
            }
            else
            {
                // Ziel liegt "links" von Start
                iIterator = -1;
            }

            // Weg gehen und Kosten summieren
            for (int k = e.sk; k != e.zk; k = k + iIterator)
            {
                iKosten += e.Feld[e.zi, k];
            }

            //Kosten speichern
            e.iKostenAbsch = iKosten;
        }
예제 #6
0
        /// <summary>
        /// Gibt ein Feld des Ergebnis Objekts auf dem Bildschirm zu Testzwecken aus
        /// </summary>
        /// <remarks>
        /// Historie:  22.05.2012  (awi) Erstellt
        /// </remarks>
        /// <param name="e">Ein Ergebnis Objekt</param>
        public void FeldAusgabe(Ergebnis e)
        {
            String s;

            // über alle Zeilen
            for (int i = 0; i < e.Feld.GetLength(0); i++)
            {
                s = ""; // String zur zeilenweisen Ausgabe
                // über alle Spalten
                for (int k = 0; k < e.Feld.GetLength(1); k++)
                {
                    s = s + e.Feld[i, k] + " , ";
                }
                Console.WriteLine(s);
            }
        }
예제 #7
0
        /// <summary>
        /// wandelt ein Feld in eine Adjazenzmatrix um
        /// </summary>
        /// <remarks>
        /// Hinweise:  Die Knoten werden Zeilenweise eingelesen, nummeriert. Also erst Zeile 0,
        ///            dann Zeile 1, usw...
        /// Historie:  22.05.2012  (awi) Erstellt
        /// </remarks>
        /// <param name="e">Ein Ergebnis Objekt</param>
        public void FeldUmwandeln(Ergebnis e)
        {
            //AdjazenzMatrix erzeugen, ein Feld der Größe m*n x m*n
            e.AdjazenzMatrix = new int[e.Feld.GetLength(0) * e.Feld.GetLength(1),
                                       e.Feld.GetLength(0) * e.Feld.GetLength(1)];

            int iZeile, iSpalte, kZeile, kSpalte;
            int iBreiteFeld = e.Feld.GetLength(1);

            // über alle Zeilen der Adjazenmatrix
            for (int i = 0; i < e.AdjazenzMatrix.GetLength(1); i++)
            {
                // Spalte und Zeile im Feld des Zeilen - Knotens berechnen
                iZeile  = (int)(i / iBreiteFeld);
                iSpalte = i % iBreiteFeld;

                // über alle Spalten der Adjazenzmatrix
                for (int k = 0; k < e.AdjazenzMatrix.GetLength(0); k++)
                {
                    // Spalte und Zeile im Feld des Spalten - Knotens berechnen
                    kZeile  = (int)(k / iBreiteFeld);
                    kSpalte = k % iBreiteFeld;

                    if (i == k)
                    {
                        // Weg auf sich selbst ist 0
                        e.AdjazenzMatrix[i, k] = 0;
                    }
                    else
                    {
                        // alle anderen Verbindungen, prüfen ob Knoten benachbart
                        if ((iZeile == kZeile && Math.Abs(iSpalte - kSpalte) == 1) ||
                            (iSpalte == kSpalte && Math.Abs(iZeile - kZeile) == 1))
                        {
                            e.AdjazenzMatrix[i, k] = e.Feld[kZeile, kSpalte];
                        }
                        else
                        {
                            // nicht benachbart, unendlich zuweisen
                            e.AdjazenzMatrix[i, k] = Konstante.UNENDLICH;
                        }
                    }
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Die Main-Methode, steuert den Programmablauf
        /// </summary>
        /// <remarks>
        /// Historie:  22.05.2012  (awi) Erstellt
        /// </remarks>
        /// <param name="args">Die Programmparameter. Es kann ein Dateiname zum Einlesen angegeben werden</param>
        static void Main(string[] args)
        {
            // Zeitmessung zur Performance-Verbesserung
            Stopwatch watch = new Stopwatch();

            watch.Start();

            // Initialisierung
            Ergebnis erg  = new Ergebnis();
            Ausgabe  ausg = new Ausgabe();
            Eingabe  eing = new Eingabe();

            String sDateinameEingabe = "";
            String sDateinameAusgabe = "";

            if (args.Length > 0)
            {
                // Parameter zum einlesen der Datei
                sDateinameEingabe = args[0];
            }
            else
            {
                // Standard Input verwenden
                sDateinameEingabe = @"Testfaelle/gebiet.txt";
            }

            // Ausgabe-Dateinamen festlegen (NameEingabedatei_Ergebnis.txt)
            sDateinameAusgabe = Path.GetDirectoryName(sDateinameEingabe)
                                + @"\" + Path.GetFileNameWithoutExtension(sDateinameEingabe) + "_Ergebnis.txt";

            try
            {
                // Datei einlesen
                eing.DateiEinlesen(sDateinameEingabe, erg);
            }
            catch (Exception e)
            {
                ausg.FehlerAusgabe("Fehler beim Einlesen der Datei: " + e.Message, sDateinameAusgabe);
                return;
            }

            // Feld in Adjazenz Matrix umwandeln
            eing.FeldUmwandeln(erg);

            // Kosten abschätzen
            KostenAbsch(erg);

            // Minimale Kosten + Weg bestimmen
            KostenMinimal(erg);

            watch.Stop();
            ausg.StringAusgabe("Ausführungszeit: " + watch.Elapsed);

            // Ergebnis ausgeben
            ausg.ErgebnisAusgabe(erg);

            // Ergebnis in Datei ausgeben
            ausg.ErgebnisDateiAusgabe(sDateinameAusgabe, erg);

            // Programm beenden
            // Console.ReadKey();
        }
예제 #9
0
        /// <summary>
        /// Errechnet einen optimalen Weg mit Kostenminimum
        /// </summary>
        /// <remarks>
        /// Hinweise:  -  errechnet eine optimale Lösung des Problems inklusive dem Weg.
        ///               Es wird ein angepasster Dijkstra-Algorithmus verwendet
        ///            -  die Adjazenzmatrix des Ergebnis Objekts muss bereits erstellt
        ///               sein
        /// Historie:  22.05.2012  (awi) Erstellt
        /// </remarks>
        /// <param name="e">Ein Ergebnis Objekt</param>
        static void KostenMinimal(Ergebnis e)
        {
            if (e.AdjazenzMatrix == null)
            {
                throw new Exception("Adjazenzmatrix im Ergebnis Objekt muss angelegt sein");
            }

            int iMinimum;
            int iKnoten;

            //Initialisierung
            int iAnzahlKnoten = e.AdjazenzMatrix.GetLength(0);

            int[] kosten     = new int[iAnzahlKnoten];      // Array für Kosten
            int[] distanz    = new int[iAnzahlKnoten];      // Array für Entfernung
            int[] vorgaenger = new int[iAnzahlKnoten];      // Array für Vorgängerknoten

            int iKostenNeu, iDistanzNeu;

            bool[] markiert = new bool[iAnzahlKnoten];

            for (int i = 0; i < iAnzahlKnoten; ++i)
            {
                // kein Knoten markiert
                markiert[i] = false;

                // Kosten auf unendlich setzen
                kosten[i] = Konstante.UNENDLICH;

                // Distanz auf unendlich setzen
                distanz[i] = Konstante.UNENDLICH;

                // keine Vorgänger
                vorgaenger[i] = Konstante.KEIN_VORGAENGER;
            }

            // Startknoten mit Kosten/Distanz 0
            kosten[e.iStartknoten]  = 0;
            distanz[e.iStartknoten] = 0;

            bool bWeitereKnoten = true;

            while (bWeitereKnoten)
            {
                // minimale Kosten initialisieren
                iMinimum = Int32.MaxValue;

                // zugehöriger (minimaler) Knoten
                iKnoten = 0;

                // Minimale Distanz ermitteln
                for (int j = 0; j < iAnzahlKnoten; j++)
                {
                    // Knoten schon markiert -> überspringen (Vermeidung von Zyklen!)
                    if (markiert[j])
                    {
                        continue;
                    }

                    // Distanz kleiner als Minimum -> neues Minimum gefunden
                    if (kosten[j] != Konstante.UNENDLICH && kosten[j] < iMinimum)
                    {
                        iMinimum = kosten[j];
                        iKnoten  = j;
                    }
                }

                // Distanz aktualisieren, wenn Zielknoten über den gefundenen
                // Minimumknoten billiger erreichbar
                for (int j = 0; j < iAnzahlKnoten; j++)
                {
                    // wenn nicht markiert und nicht Verbindung gleicher Knoten und Verbindung vorhanden
                    if (!markiert[j] &&
                        iKnoten != j &&
                        e.AdjazenzMatrix[iKnoten, j] != Konstante.UNENDLICH)
                    {
                        // Neuberechnung von Distanz und Kosten
                        iKostenNeu  = kosten[iKnoten] + e.AdjazenzMatrix[iKnoten, j];
                        iDistanzNeu = distanz[iKnoten] + 1;

                        // besteht Verbesserung? Unendlich ist immer zu verbessern,
                        // ansonsten vergleichen, ob neuer Wert besser als alter Wert
                        // oder, Kosten gleich, kürzeren Weg wählen
                        if (kosten[j] == Konstante.UNENDLICH ||
                            kosten[j] > iKostenNeu ||
                            (kosten[j] == iKostenNeu && distanz[j] > iDistanzNeu))
                        {
                            // Verbesserung gefunden
                            kosten[j]     = iKostenNeu;
                            distanz[j]    = iDistanzNeu;
                            vorgaenger[j] = iKnoten;
                        }
                    }
                }

                // gerade bestimmten Minimumknoten markieren
                markiert[iKnoten] = true;

                // sind noch Knoten nicht markiert -> weiter, sonst Ende
                bWeitereKnoten = false;
                for (int j = 0; j < iAnzahlKnoten && !bWeitereKnoten; j++)
                {
                    bWeitereKnoten = !markiert[j];
                }
            }

            // kuerzester Weg speichern

            // Länge des kürzesten Weges
            e.kuerzesterWeg = new int[distanz[e.iZielknoten] + 1];

            // Vorgänger verfolgen bis zum Ziel ("Rückwärtssuche")

            // Rückwärtssuche startet beim Zielknoten
            iKnoten = e.iZielknoten;

            // Ergebnis Array von hinten befüllen
            int kuerzesterWegIterator = distanz[e.iZielknoten];

            while (vorgaenger[iKnoten] != Konstante.KEIN_VORGAENGER)
            {
                // Knoten speichern
                e.kuerzesterWeg[kuerzesterWegIterator] = iKnoten;
                // Vorgänger festlegen
                iKnoten = vorgaenger[iKnoten];
                kuerzesterWegIterator--;
            }

            // Startknoten speichern
            e.kuerzesterWeg[0] = e.iStartknoten;

            // Minimalkosten speichern
            e.iKostenMinimal = kosten[e.iZielknoten];
        }
예제 #10
0
        /// <summary>
        /// Liest eine Datei ein ein und speichert in Ergebnis Objekt
        /// </summary>
        /// <remarks>
        /// Hinweise:  Löst verschiedene Ausnahmen aus, wenn Datei nicht geladen werden kann oder Datei
        ///            fehlerhaft
        ///            S, Z werden als 0 im Feld markiert
        /// Historie:  22.05.2012  (awi) Erstellt
        /// </remarks>
        /// <param name="sDateiname">Ein String mit einem Dateinamen</param>
        /// <param name="e">Ein Ergebnis Objekt</param>
        public void DateiEinlesen(String sDateiname, Ergebnis e)
        {
            bool   bStartgefunden = false;
            bool   bZielgefunden = false;
            int    iSpalten = 0;
            int    iZeile = 0;
            String sTmp, sZelle, sTmpAusn;

            String[] sTmpArr;
            int      iTmp;

            StreamReader sr;

            int[,] tmpFeld = new int[Konstante.MAX_ZEILE, Konstante.MAX_SPALTE];

            if (File.Exists(sDateiname))
            {
                // Einlesen mit ISO-8859-1 (Westeuropäisch), wird wegen Umlauten in Kommentar verwendet
                sr = new StreamReader(File.Open(sDateiname, FileMode.Open), Encoding.GetEncoding(28591));
            }
            else
            {
                throw new FileNotFoundException("Die angegebene Datei wurde nicht gefunden");
            }

            if (sr.Peek() == -1)
            {
                throw new FileLoadException("Die angegebene Datei ist leer");
            }

            // erste Zeile lesen, erwartet Kommentar
            sTmp = sr.ReadLine();
            if (sTmp.StartsWith(";"))
            {
                // Kommentar in Ergebnis Objekt speichern
                e.sKommentar = sTmp.Substring(1).Trim();
            }
            else
            {
                throw new FileLoadException("Die angegebene Datei erhält eine fehlerhafte 1. Zeile");
            }

            // weitere Zeilen durchlaufen
            while (sr.Peek() >= 0)
            {
                if (iZeile >= Konstante.MAX_ZEILE)
                {
                    sTmpAusn = String.Format("Das Feld darf nicht mehr als {0} Zeilen haben.",
                                             Konstante.MAX_ZEILE);
                    throw new FileLoadException(sTmpAusn);
                }

                sTmp = sr.ReadLine();
                if (sTmp.StartsWith(";"))
                {
                    // Kommentar gefunden
                    continue;
                }

                // Zeile aufgrund von ',' trennen
                sTmpArr = sTmp.Split(',');
                if (iZeile == 0)
                {
                    // erste Zeile --> Spaltenzahl festlegen
                    iSpalten = sTmpArr.GetLength(0);
                    if (iSpalten > Konstante.MAX_SPALTE)
                    {
                        sTmpAusn = String.Format("Es darf nicht mehr als {0} Spalten geben.",
                                                 Konstante.MAX_SPALTE);
                        throw new FileLoadException(sTmpAusn);
                    }
                }
                else
                {
                    // prüfen ob einheitliche Spaltenlänge
                    if (sTmpArr.GetLength(0) != iSpalten)
                    {
                        throw new FileLoadException("Unterschiedliche Spaltenanzahl in Datei gefunden.");
                    }
                }

                // über alle Einträge im getrennten Zeilenstring
                for (int k = 0; k < sTmpArr.GetLength(0); k++)
                {
                    // Leerzeichen vorne und hinten abschneiden / Groß- / Kleinschreibung nicht beachten
                    sZelle = sTmpArr[k].Trim().ToUpper();

                    if (sZelle.Equals("S"))
                    {
                        // Startzelle gefunden
                        if (bStartgefunden)
                        {
                            // Startzelle wurde bereits gefunden
                            throw new FileLoadException("Es darf nur eine Startzelle definiert sein.");
                        }

                        // Startzelle wird in Feld als 0 gespeichert
                        iTmp           = 0;
                        bStartgefunden = true;

                        //Startknoten festlegen
                        e.si           = iZeile;
                        e.sk           = k;
                        e.iStartknoten = iZeile * iSpalten + k;
                    }
                    else if (sZelle.Equals("Z"))
                    {
                        // Zielzelle gefunden
                        if (bZielgefunden)
                        {
                            // Ziel bereits gefunden
                            throw new FileLoadException("Es darf nur eine Zielzelle definiert sein.");
                        }

                        // Zielzelle wird in Feld als 0 gespeichert
                        iTmp          = 0;
                        bZielgefunden = true;

                        //Zielknoten festlegen
                        e.zi          = iZeile;
                        e.zk          = k;
                        e.iZielknoten = iZeile * iSpalten + k;
                    }
                    else
                    {
                        // wenn nicht S oder Z muss ein Zahlenwert vorliegen:
                        try
                        {
                            iTmp = Int32.Parse(sZelle);
                        }
                        catch
                        {
                            sTmpAusn = "Es sind nur ganzzahlige Zahlenwerte "
                                       + "zwiwschen 1 und 9 und S,Z in den Zellen erlaubt.";
                            throw new ArithmeticException(sTmp);
                        }

                        // liegt Zahlenwert im definierten Bereich?
                        if (iTmp < 1 || iTmp > 9)
                        {
                            sTmpAusn = "Es sind nur Zahlenwerte"
                                       + "zwischen 1 und 9 erlaubt.";
                            throw new FileLoadException(sTmpAusn);
                        }
                    }

                    // gelesenen Wert in temporären Feld speichern
                    tmpFeld[iZeile, k] = iTmp;
                }

                iZeile++; // nächste Zeile
            }
            sr.Close();

            // sind Start / Ziel gefunden?
            if (!bStartgefunden)
            {
                throw new FileLoadException("In der Datei muss eine Startzelle angegeben sein.");
            }

            if (!bZielgefunden)
            {
                throw new FileLoadException("In der Datei muss eine Zielzelle angegeben sein.");
            }

            //tmpFeld in Ergebnis - Feld übertragen
            e.Feld = new int[iZeile, iSpalten];
            for (int i = 0; i < iZeile; i++)
            {
                for (int k = 0; k < iSpalten; k++)
                {
                    e.Feld[i, k] = tmpFeld[i, k];
                }
            }
        }