C# :: Aufgabe #96 :: Lösung #2

3 Lösungen Lösungen öffentlich
#96

Das Damenproblem (Teil II)

Fortgeschrittener - C# von ElPapito - 07.05.2015 um 11:45 Uhr
Das verallgemeinerte Damenproblem besteht aus einem nxn Schachfeld und n Damen.
Die Aufgabe besteht darin die n Damen so zu positionieren, dass sie sich gegenseitig nicht bedrohen, d.h. es dürfen keine zwei Damen in der gleichen Zeile/Spalte/Diagonale stehen.

Schreibe ein kleines Programm, welches für n = 1, ..., 13 ausgibt wie viele Lösungen existieren.
#2
4 Kommentare
vote_ok
von DaBaschdi (120 Punkte) - 06.08.2015 um 09:31 Uhr
Hier mein Lösungsvorschlag. Da ich noch nicht sehr lange programmiere, mangelt es mir noch am effizienten Design und dem richtigen Kommentieren. Ich hoffe dennoch, dass mein Code verständlich ist. Eine Kontrolle des einzugebenden n habe ich mir erspart.

Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Damenproblem
{
    //Sebastian Woll, 06.08.15

    class Program
    {
        static int n; //Feldlänge
        static int WievieleFelder; //Vermutete Menge der zu findenden Felder
        static string[][,] Felder = new string[WievieleFelder][,]; //Felder werden gespeichert
        static int CounterFelder = 0; // x-tes gefundenes Feld
        static int CounterRandom = 0; /* Seed des Zufallsgenerators für "mehr" Zufall 
                                       * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                                       * Mit diesem Counter werden bei n=8 immer 92 Lösungen gefunden,
                                       * ohne ihn erzeugt jeder Durchlauf ein anderes Ergebnis!                                        
                                       */
        static int CounterVergleichFALSE = 0; //Dient zur Terminierung des Programms nach zu vielen Fehlversuchen

        static void Main(string[] args)
        {
            Console.Write("\nWelche Länge sollen die Felder haben?\t");
            n = Convert.ToInt32(Console.ReadLine());
            WievieleFelder = n * n * n;
            Felder = new string[WievieleFelder][,];
            for (int i = 0; i < Felder.GetUpperBound(0); i++) //JaggedArray wird gefüllt
            {
                Felder[i] = new string[n, n];
                Felder[i][0, 0] = "."; //Der Punkt dient als Zeichen für "FREIES FELD"
            }
        //Feld generieren
        NeuesFeld:

            //Variablen deklarieren/zurücksetzen
            string[,] Feld = new string[n, n];
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    Feld[i, j] = ".";
                }
            }
            Random Zufall = new Random(CounterRandom);
            CounterRandom++;
            int x, y, CounterDame, CounterWuerfeln;
            CounterWuerfeln = 0;
            CounterDame = 0;
            //Variablen deklarieren/zurücksetztn ENDE

            //Feld füllen
            do
            {
            NeuWuerfeln:
                CounterWuerfeln++;
                x = Zufall.Next(n); //Dame bekommt zufällige Position
                y = Zufall.Next(n);
                if (Feld[x, y] == ".") // Ist die Position frei und nicht bedroht?
                {
                    Felderstreichen(x, y, Feld, CounterDame);
                    CounterDame++; //Nächste Dame
                }
                else
                {
                    if (CounterWuerfeln > n * n * 10) //Wuerfeln gegen endlos? / Position nicht lösbar?
                    {
                        break; //Abbruch bei zu langem Wuerfeln
                    }
                    else
                    {
                        goto NeuWuerfeln;
                    }
                }
            } while (CounterDame < n);
            //Feld füllen ENDE

            //Feld generieren ENDE

            if (CounterVergleichFALSE > 1000) //Wenn nach 1000 Treffern kein neues Feld gefunden wird, endet das Programm mit der Ausgabe des Zählers
            {
                Console.WriteLine("\nEs wurden {0} Felder gefunden.", CounterFelder);
            }
            else
            {
                //Damen alle da?
                if (CounterDame == n)
                {
                    //Feld schonmal gefunden?
                    if (ArraysVergleichen(Feld, Felder) == false) //Verlgeich funktioniert nicht
                    {
                        CounterVergleichFALSE = 0;
                        FeldAusgeben(Feld);
                        Felder[CounterFelder] = Feld;
                        CounterFelder++;
                        //FeldAusgeben(Feld);
                        if (CounterFelder < WievieleFelder - 1) //Weniger als WievieleFelder Felder wurden gefunden
                        {
                            //CounterFelder++;
                            goto NeuesFeld;
                        }
                        else
                        {
                            Console.WriteLine("Es wurden {0} Felder gefunden", CounterFelder);
                        }
                    }
                    else //Feld wurde schonmal gefunden
                    {
                        CounterVergleichFALSE++;
                        goto NeuesFeld;
                    }
                    //Feld schonmal gefunden? ENDE
                }
                else //Damen weniger als n
                {
                    goto NeuesFeld;
                }
                //Damen alle da? ENDE
            }

            Console.ReadLine();
        }//Ende Main


        //Felder streichen
        static void Felderstreichen(int x, int y, string[,] Feld, int CounterDame)
        {
            //Der Strich "-" bedeutet, dass das Feld bedroht ist.
            //Striche waagerecht und senkrecht
            for (int i = 0; i < n; i++)
            {
                Feld[x, i] = "-";
                Feld[i, y] = "-";
            }
            Feld[x, y] = "D";

            //Diagonale nach rechts unten
            for (int i = 1; (i < n - x) && (i < n - y); i++)
            {
                Feld[x + i, y + i] = "-";
            }
            //Diagonale nach links oben
            for (int i = 1; (i <= x) && (i <= y); i++)
            {

                Feld[x - i, y - i] = "-";

            }
            //Diagonale nach rechts oben
            for (int i = 1; (i <= x) && (i < n - y); i++)
            {
                Feld[x - i, y + i] = "-";
            }

            //Diagonale nach links unten
            for (int i = 1; (i < n - x) && (i <= y); i++)
            {
                Feld[x + i, y - i] = "-";
            }

        }//FelderstreichenEnde

        //FeldAusgeben
        static void FeldAusgeben(string[,] Feld)
        {
            Console.WriteLine();
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    Console.Write(Feld[i, j] + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        } //FeldAusgeben ENDE


        //Arrays Vergleichen
        static bool ArraysVergleichen(string[,] NeuesFeld, string[][,] GefundeneFelder)
        {
            int CounterStimmt = 0;
            for (int i = 0; i < WievieleFelder - 1; i++)
            {
                CounterStimmt = 0;
                for (int j = 0; j < n; j++)
                {
                    for (int h = 0; h < n; h++)
                    {
                        if (NeuesFeld[j, h] == GefundeneFelder[i][j, h])
                        {
                            CounterStimmt++;
                        }
                    }
                }
                if (CounterStimmt == n * n)
                {
                    return true;
                }
            }
            return false;
        } //ArraysVergleichen ENDE

        //VERGLEICH FUNKTIONIERT NICHT, wurde durch ArrayVergleichen ersetzt
        // static bool IstFeldSchonVorhanden(string[,] NeuesFeld, string[][,] GefundeneFelder)
        //{
        //    for (int i = 0; i < WievieleFelder - 1; i++)
        //    {
        //        if (NeuesFeld.Equals(GefundeneFelder[i]))
        //        {
        //            FeldAusgeben(NeuesFeld);
        //            Console.WriteLine();
        //            FeldAusgeben(GefundeneFelder[i]);
        //            return true;
        //        }
        //    }
        //    return false;
        //}

        //Sebastian Woll, 06.08.15
    }
}

Kommentare:

eulerscheZhl

Punkte: 5230

110 Aufgaben
76 Lösungen
64 Kommentare

#1
21.08.2015 um 09:40 Uhr
Für n=4 landest du in einer Endlosschleife und für n=8 findest du nur eine Lösung.
post_arrow
205 0

DaBaschdi

Punkte: 120


3 Lösungen
2 Kommentare

#2
21.08.2015 um 09:53 Uhr
Das mit den kleineren Zahlen habe ich später auch gemerkt.
Allerdings hab ich bei n=8 wirklich immer 92 Lösungen.

Das generelle Problem meines Programms ist ja, dass ich wirklich jede einzelne Dame per Zufall setze, also ohne System. Dadurch bekomme ich gerade bei den größeren Zahlen auch immer "zufällige" Ergebnisse. Daher kanns durchaus sein, dass die Zahlen meiner Versuche selten und/oder nicht reproduzierbar sind.

Als Endlösung ist es also völlig ungeeignet.
post_arrow
206 0

eulerscheZhl

Punkte: 5230

110 Aufgaben
76 Lösungen
64 Kommentare

#3
21.08.2015 um 10:00 Uhr
Dass ich ein anderes Ergebnis erhalte, kann damit zusammenhängen, dass ich vermutlich ein anderes System verwende als du (Linux mit Mono zum Ausführen von .net Code).

Wenn man nur eine Lösung finden will, ist Random durchaus legitim. Wenn man alle Möglichkeiten finden will, sollte man aber auch alle durchprobieren. Das spart Rechenzeit (weil du eine Lösung nicht mehrfach prüfst) und du kannst sicher sein, alle gefunden zu haben.

Die Endlosschleife kommt daher, dass du in Zeile 117 nicht CounterVergleichFALSE++; schreibst, bevor du die Iteration erneut startest.
Viel Spaß und Erfolg weiterhin beim Programmieren lernen :)
post_arrow
207 0

DaBaschdi

Punkte: 120


3 Lösungen
2 Kommentare

#4
21.08.2015 um 10:08 Uhr
Ok, ich programmiere unter Win7/8.1.
Deinen Vorschlag probiere ich demnächst mal aus, vielen Dank für den Tipp! :)
post_arrow
208 0
Bitte melden Sie sich an um eine Kommentar zu schreiben.
Kommentar schreiben