Heim >Java >javaLernprogramm >Fallstudie: Das Nine-Tails-Problem

Fallstudie: Das Nine-Tails-Problem

王林
王林Original
2024-08-10 06:48:03478Durchsuche

Das Neun-Schwänze-Problem kann auf das Problem des kürzesten Weges reduziert werden.
Das Neun-Schwänze-Problem ist wie folgt. Neun Münzen werden in einer Drei-mal-Drei-Matrix platziert, einige mit der Vorderseite nach oben und andere mit der Vorderseite nach unten. Ein legaler Zug besteht darin, eine aufgedeckte Münze zu nehmen und sie zusammen mit den angrenzenden Münzen umzudrehen (davon ausgenommen sind diagonal angrenzende Münzen). Ihre Aufgabe besteht darin, die Mindestanzahl an Zügen zu finden, die dazu führt, dass alle Münzen verdeckt liegen. Beginnen Sie beispielsweise mit den neun Münzen, wie in Abbildung unten (a) gezeigt. Nachdem Sie die zweite Münze in der letzten Reihe geworfen haben, sehen die neun Münzen nun wie in Abbildung unten (b) dargestellt aus. Nachdem Sie die zweite Münze in der ersten Reihe geworfen haben, sind alle neun Münzen verdeckt, wie in Abbildung unten (c) gezeigt.

Case Study: The Nine Tails Problem

Wir werden ein Programm schreiben, das den Benutzer auffordert, einen Anfangszustand der neun Münzen einzugeben, und die Lösung anzeigt, wie im folgenden Beispiellauf gezeigt.

Geben Sie die ersten neun Münzen Hs und Ts ein: HHHTTTHHH
Die Schritte zum Werfen der Münzen sind
HHH
TTT
HHH
HHH
THT
TTT
TTT
TTT
TTT

Jeder Zustand der neun Münzen stellt einen Knoten im Diagramm dar. Beispielsweise entsprechen die drei Zustände in der Abbildung oben drei Knoten im Diagramm. Der Einfachheit halber verwenden wir eine 3 * 3-Matrix zur Darstellung aller Knoten und verwenden 0 für Köpfe und 1 für Schwänze. Da es neun Zellen gibt und jede Zelle entweder 0 oder 1 ist, gibt es insgesamt 2^9 (512) Knoten mit der Bezeichnung 0, 1, . . . und 511, wie in der Abbildung unten gezeigt.

Case Study: The Nine Tails Problem

Wir weisen eine Kante vom Knoten v zu u zu, wenn es eine legale Bewegung von u nach v gibt. Die folgende Abbildung zeigt eine Teilgrafik. Beachten Sie, dass es eine Kante von 511 bis 47 gibt, da Sie eine Zelle im Knoten 47 umdrehen können, um zum Knoten 511 zu werden.

Case Study: The Nine Tails Problem

Der letzte Knoten in der Abbildung unten stellt den Zustand von neun verdeckten Münzen dar. Der Einfachheit halber nennen wir diesen letzten Knoten den Zielknoten. Daher erhält der Zielknoten die Bezeichnung 511. Angenommen, der Anfangszustand des Neun-Schwanz-Problems entspricht dem Knoten s. Das Problem reduziert sich darauf, einen kürzesten Pfad vom Knoten s zum Zielknoten zu finden, was dem Finden eines kürzesten Pfads vom Knoten s zum Zielknoten in einem BFS-Baum mit der Wurzel entspricht der Zielknoten.

Case Study: The Nine Tails Problem

Die Aufgabe besteht nun darin, einen Graphen zu erstellen, der aus 512 Knoten mit den Bezeichnungen 0, 1, 2, ... besteht. . . , 511 und Kanten zwischen den Knoten. Sobald das Diagramm erstellt ist, erhalten Sie einen BFS-Baum mit der Wurzel am Knoten 511. Im BFS-Baum können Sie den kürzesten Weg von der Wurzel zu jedem Scheitelpunkt finden. Wir erstellen eine Klasse mit dem Namen NineTailModel, die die Methode enthält, um einen kürzesten Pfad vom Zielknoten zu jedem anderen Knoten zu erhalten. Das Klassen-UML-Diagramm ist in der Abbildung unten dargestellt.

Case Study: The Nine Tails Problem

Optisch wird ein Knoten in einer 3 * 3-Matrix mit den Buchstaben H und T dargestellt. In unserem Programm verwenden wir ein eindimensionales Array aus neun Zeichen, um einen Knoten darzustellen. Beispielsweise wird der Knoten für Scheitelpunkt 1 in der Abbildung unten als {'H', 'H', 'H' dargestellt , 'H', 'H', 'H', 'H', 'H' , 'T'} im Array.

Case Study: The Nine Tails Problem

Die Methode getEdges() gibt eine Liste von Edge-Objekten zurück.

Die Methode getNode(index) gibt den Knoten für den angegebenen Index zurück. Beispielsweise gibt getNode(0) den Knoten zurück, der neun Hs enthält. getNode(511) gibt den Knoten zurück, der neun Ts enthält. Die Methode getIndex(node) gibt den Index des Knotens zurück.

Beachten Sie, dass das Datenfeld Baum als geschützt definiert ist, sodass über die Unterklasse WeightedNineTail darauf zugegriffen werden kann.

Die Methode getFlippedNode(char[] node, int position) dreht den Knoten an der angegebenen Position und seinen angrenzenden Positionen um. Diese Methode gibt den Index des neuen Knotens zurück.

Die Position ist ein Wert von 0 bis 8, der auf eine Münze im Knoten zeigt, wie in der folgenden Abbildung dargestellt.

Case Study: The Nine Tails Problem

Zum Beispiel drehen Sie den Knoten 56 in der Abbildung unten an der Position 0 um, und Sie erhalten den Knoten 51. Wenn Sie Knoten 56 an Position 1 umdrehen, erhalten Sie Knoten 47.

Case Study: The Nine Tails Problem

Die Methode flipACell(char[] node, int row, int columns) dreht einen Knoten in der angegebenen Zeile und Spalte um. Wenn Sie beispielsweise den Knoten 56 in Zeile 0 und Spalte 0 umdrehen, ist der neue Knoten 408. Wenn Sie den Knoten 56 in Zeile 2 und Spalte 0 umdrehen, ist der neue Knoten 30.

Der folgende Code zeigt den Quellcode für NineTailModel.java.

import java.util.*;

public class NineTailModel {
    public final static int NUMBER_OF_NODES = 512;
    protected AbstractGraph<Integer>.Tree tree; // Define a tree

    /** Construct a model */
    public NineTailModel() {
        // Create edges
        List<AbstractGraph.Edge> edges = getEdges();

        // Create a graph
        UnweightedGraph<Integer> graph = new UnweightedGraph<>(edges, NUMBER_OF_NODES);

        // Obtain a BSF tree rooted at the target node
        tree = graph.bfs(511);
    }

    /** Create all edges for the graph */
    private List<AbstractGraph.Edge> getEdges() {
        List<AbstractGraph.Edge> edges = new ArrayList<>(); // Store edges

        for (int u = 0; u < NUMBER_OF_NODES; u++) {
            for (int k = 0; k < 9; k++) {
                char[] node = getNode(u); // Get the node for vertex u
                if (node[k] == 'H') {
                    int v = getFlippedNode(node, k);
                    // Add edge (v, u) for a legal move from node u to node v
                    edges.add(new AbstractGraph.Edge(v, u));
                }
            }
        }

        return edges;
    }

    public static int getFlippedNode(char[] node, int position) {
        int row = position / 3;
        int column = position % 3;

        flipACell(node, row, column);
        flipACell(node, row - 1, column);
        flipACell(node, row + 1, column);
        flipACell(node, row, column - 1);
        flipACell(node, row, column + 1);

        return getIndex(node);
    }

    public static void flipACell(char[] node, int row, int column) {
        if (row >= 0 && row <= 2 && column >= 0 && column <= 2) {
            // Within the boundary
            if (node[row * 3 + column] == 'H')
                node[row * 3 + column] = 'T'; // Flip from H to T
            else
                node[row * 3 + column] = 'H'; // Flip from T to H
            }
    }

    public static int getIndex(char[] node) {
        int result = 0;

        for (int i = 0; i < 9; i++)
            if (node[i] == 'T')
                result = result * 2 + 1;
            else
                result = result * 2 + 0;

        return result;
    }

    public static char[] getNode(int index) {
        char[] result = new char[9];

        for (int i = 0; i < 9; i++) {
            int digit = index % 2;
            if (digit == 0)
                result[8 - i] = 'H';
            else
                result[8 - i] = 'T';
            index = index / 2;
        }

        return result;
    }

    public List<Integer> getShortestPath(int nodeIndex) {
        return tree.getPath(nodeIndex);
    }

    public static void printNode(char[] node) {
        for (int i = 0; i < 9; i++)
            if (i % 3 != 2)
                System.out.print(node[i]);
            else
                System.out.println(node[i]);

        System.out.println();
    }
}

Der Konstruktor (Zeilen 8–18) erstellt einen Graphen mit 512 Knoten, und jede Kante entspricht der Bewegung von einem Knoten zum anderen (Zeile 10). Aus dem Diagramm wird ein BFS-Baum erhalten, der am Zielknoten 511 verwurzelt ist (Zeile 17).

Um Kanten zu erstellen, prüft die Methode getEdges (Zeilen 21–37) jeden Knoten u, um zu sehen, ob er auf einen anderen Knoten v umgedreht werden kann. Wenn ja, fügen Sie (v, u) zur Liste Edge hinzu (Zeile 31). Die Methode getFlippedNode(node, position) findet einen umgedrehten Knoten, indem sie eine H-Zelle und ihre Nachbarn in einem Knoten umdreht (Zeilen 43–47). Die Methode flipACell(node, row, Column) dreht tatsächlich eine H-Zelle und ihre Nachbarn in einem Knoten um (Zeilen 52–60).

Die Methode getIndex(node) wird auf die gleiche Weise implementiert wie die Konvertierung einer Binärzahl in eine Dezimalzahl (Zeilen 62–72). Die Methode getNode(index) gibt einen Knoten zurück, der aus den Buchstaben H und T besteht (Zeilen 74–87).

Die Methode getShortestpath(nodeIndex) ruft die Methode getPath(nodeIndex)
auf Methode zum Abrufen eines Scheitelpunkts auf dem kürzesten Weg vom angegebenen Knoten zum Zielknoten
(Zeilen 89–91).

Die Methode printNode(node) zeigt einen Knoten auf der Konsole an (Zeilen 93–101).

Der folgende Code stellt ein Programm dar, das den Benutzer auffordert, einen Anfangsknoten einzugeben, und die Schritte zum Erreichen des Zielknotens anzeigt.

import java.util.Scanner;

public class NineTail {

    public static void main(String[] args) {
        // Prompt the user to enter nine coins' Hs and Ts
        System.out.print("Enter the initial nine coins Hs and Ts: ");
        Scanner input = new Scanner(System.in);
        String s = input.nextLine();
        char[] initialNode = s.toCharArray();

        NineTailModel model = new NineTailModel();
        java.util.List<Integer> path = model.getShortestPath(NineTailModel.getIndex(initialNode));

        System.out.println("The steps to flip the coins are ");
        for (int i = 0; i < path.size(); i++)
            NineTailModel.printNode(NineTailModel.getNode(path.get(i).intValue()));
    }

}

Das Programm fordert den Benutzer auf, einen Anfangsknoten mit neun Buchstaben mit einer Kombination aus Hs und Ts als Zeichenfolge in Zeile 8 einzugeben, um daraus ein Array von Zeichen zu erhalten Die Zeichenfolge (Zeile 9) erstellt ein Diagrammmodell, um einen BFS-Baum zu erhalten (Zeile 11), und erhält einen kürzesten Pfad vom Anfangsknoten zum
Zielknoten (Zeilen 12–13) und zeigt die Knoten im Pfad an (Zeilen 16–18).

Das obige ist der detaillierte Inhalt vonFallstudie: Das Nine-Tails-Problem. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:GraphdurchquerungenNächster Artikel:Graphdurchquerungen