0

0

案例研究:九尾问题

王林

王林

发布时间:2024-08-10 09:24:46

|

460人浏览过

|

来源于dev.to

转载

九尾问题可以简化为最短路径问题。
九尾问题如下。九枚硬币被放置在一个三乘三的矩阵中,一些面朝上,一些面朝下。合法的举动是取出一枚正面朝上的硬币,并将其连同与其相邻的硬币一起翻转(这不包括对角相邻的硬币)。您的任务是找到导致所有硬币面朝下的最少移动次数。例如,从九个硬币开始,如下图(a)所示。当你翻转最后一排的第二枚硬币后,九枚硬币现在如下图(b)所示。翻转第一排第二枚硬币后,九枚硬币全部面朝下,如下图(c)所示。

案例研究:九尾问题

我们将编写一个程序,提示用户输入九个硬币的初始状态并显示解决方案,如下面的示例运行所示。

输入前九个硬币hs和ts:hhhttthhh
抛硬币的步骤是
哈哈哈
tt
哈哈哈
哈哈哈
tht
tt
tt
tt
tt

九个硬币的每个状态代表图中的一个节点。例如,上图中的三个状态对应图中的三个节点。为了方便起见,我们使用 3 * 3 矩阵来表示所有节点,并使用 0 表示头部,1 表示尾部。由于有 9 个单元,每个单元要么是 0 要么是 1,所以总共有 2^9 (512) 个节点,标记为 01、 。 。 。 、511,如下图

案例研究:九尾问题

如果存在从uv的合法移动,我们将从节点v分配一条边到u。下图显示了部分图表。请注意,从51147有一条边,因为您可以翻转节点47中的单元格以成为节点511

案例研究:九尾问题

下图中最后一个节点代表九个面朝下的硬币的状态。为了方便起见,我们将最后一个节点称为目标节点。因此,目标节点被标记为511。假设九尾问题的初始状态对应节点s。问题简化为寻找从节点s到目标节点的最短路径,相当于在以目标节点为根的bfs树中寻找从节点s到目标节点的最短路径。

案例研究:九尾问题

现在的任务是构建一个由 512 个节点组成的图,标记为012、。 。 。 ,511,以及节点之间的边。创建图后,获取以节点511为根的 bfs 树。从bfs树中,你可以找到从根到任意顶点的最短路径。我们将创建一个名为ninetailmodel的类,其中包含获取从目标节点到任何其他节点的最短路径的方法。类uml图如下图所示。

案例研究:九尾问题

酷表ChatExcel
酷表ChatExcel

北大团队开发的通过聊天来操作Excel表格的AI工具

下载

在视觉上,节点以字母 ht 的 3 * 3 矩阵表示。在我们的程序中,我们使用九个字符的一维数组来表示一个节点。例如,下图中顶点 1 的节点表示为 {'h', 'h', 'h', 'h', 'h', 'h ', 'h', 'h', 't'} 在数组中。

案例研究:九尾问题

getedges() 方法返回edge 对象的列表。

getnode(index) 方法返回指定索引的节点。例如,getnode(0) 返回包含 9 个 h 的节点。 getnode(511) 返回包含 9 个 t 的节点。 getindex(node) 方法返回节点的索引。

请注意,数据字段tree被定义为受保护,以便可以从weightedninetail子类访问它。

getflippednode(char[] node, intposition)方法翻转指定位置及其相邻位置的节点。该方法返回新节点的索引。

position是

08之间的值,指向节点中的一枚币,如下图

案例研究:九尾问题

例如下图中的节点

56,在0位置翻转,就会得到节点51。如果你在位置1翻转节点56,你将得到节点47.

案例研究:九尾问题

flipacell(char[] node, int row, int column)

方法翻转指定行和列处的节点。例如,如果翻转第 00 处的节点 56,则新节点为 408。如果翻转行2和列0的节点56,新节点是30. 下面的代码展示了 ninetailmodel.java 的源代码。

import java.util.*;

public class ninetailmodel {
    public final static int number_of_nodes = 512;
    protected abstractgraph.tree tree; // define a tree

    /** construct a model */
    public ninetailmodel() {
        // create edges
        list edges = getedges();

        // create a graph
        unweightedgraph 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 getedges() {
        list 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 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();
    }
}


构造函数(第 8-18 行)创建一个包含 512 个节点的图,每条边对应于从一个节点到另一个节点的移动(第 10 行)。从图中,得到一棵以目标节点

511

为根的bfs树(第17行)。 为了创建边,

getedges

方法(第21-37行)检查每个节点u以查看它是否可以翻转到另一个节点v。如果是这样,请将 (v, u) 添加到 edge 列表(第 31 行)。 getflippednode(node,position) 方法通过翻转节点中的 h 单元及其邻居来查找翻转节点(第 43-47 行)。 flipacell(node, row, column) 方法实际上翻转节点中的 h 单元格及其邻居(第 52-60 行)。 getindex(node)

方法的实现方式与将二进制数转换为十进制数相同(第62-72行)。

getnode(index) 方法返回一个由字母 ht 组成的节点(第 74-87 行)。 getshortestpath(nodeindex)

方法调用

getpath(nodeindex) 获取从指定节点到目标节点的最短路径中的顶点的方法 (第 89-91 行).
printnode(node)
方法在控制台上显示一个节点(第 93-101 行)。

下面的代码给出了一个程序,提示用户输入初始节点并显示到达目标节点的步骤。

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 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()));
    }

}

程序在第 8 行提示用户输入由 9 个字母组成的初始节点,并以

h
s 和

t

s 的组合作为字符串,从字符串中获取字符数组(第 9 行),创建一个图形模型获取bfs树(第11行),获取从初始节点到的最短路径 目标节点(第 12-13 行),并显示路径中的节点(第 16-18 行)。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

833

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

738

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

734

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16926

2023.08.03

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

2

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Git 教程
Git 教程

共21课时 | 2.7万人学习

Git版本控制工具
Git版本控制工具

共8课时 | 1.5万人学习

Git中文开发手册
Git中文开发手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号