数据结构-16枚硬币问题

本题主要考查对图的结构和图的广度优先遍历操作的掌握。
实现效果:

什么是图?
定义:图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。图又分为有向图、无向图,有向图即边为有向边的图,无向图即边没有方向的图。

图的两种遍历(深度优先遍历、广度优先遍历)

深度优先遍历:(Depth First Search),简称DFS,其遍历类似树的前序遍历。
它从图中某个结点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到。若图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中的所有顶点都被访问到为止。

广度优先搜索(Breadth First Search),简称DFS,其遍历类似树的层次遍历。
假设从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点“先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时图中尚有顶点未被访问,则选中图中一个未曾被访问的顶点 作起始点,重复上述过程直至图中所有顶点都被访问到为止。
eg:

用邻接表存储方式表示图

顶点 邻接点
V0 V1 、V2
V1 V0、V5、V6
V2 V0、V4、V5
V3 V5、V6
V4 V2
V5 V1、V2、V3
V6 V1、V3

深度优先遍历:V0,V1,V5,V3,V6,V2,V4.
广度优先遍历:V0,V1,V2,V5,V6,V3,V4.

首先根据图1分析16枚硬币问题的游戏规则,一枚硬币只有正反面两个结果。当翻动一枚硬币,该硬币周围(只包括上、下、左、右)的硬币也要翻动。我们不妨将16枚硬币正反状态看作一个16位的二进制数字(0表示正面,1表示反面),十六枚硬币正反状态表示的二进制数作为图的一个顶点(例如:只有第一枚硬币处于反面,其他十五枚硬币处于正面,那么它表示而二进制数为1000000000000000)。然后翻动一枚为正面的硬币,记录此时16枚硬币表示的16位二进制数(即边的另一个顶点),接着根据这两个顶点构建一条边。构建图的所有边,从所有硬币都是正面(0000000000000000)到所有硬币都是反面(1111111111111111),构建所有可能的边。代码如下(为了方便顶点为十进制数)

/** 创建图的所有边 */
private List<AbstractGraph.Edge> getEdges() {List<AbstractGraph.Edge> edges =new ArrayList<AbstractGraph.Edge>();for (int u = 0; u < NUMBER_OF_NODES; u++) {for (int k = 0; k < 16; k++) {char[] node = getNode(u);if (node[k] == 'H') {//getFlippedNode为翻转硬币后求得十进制数(返回值根据翻转规则设定)int v = getFlippedNode(node, k); // 添加边缘(V,U)的法律行动从节点U到节点Vedges.add(new AbstractGraph.Edge(v, u));}}}return edges;
}

图构建好后,硬币的最终状态为所有硬币为反面(1111111111111111即目标顶点),16硬币游戏开始之前有一个初始状态(未知)。然后我们用目标顶点作为图遍历的起点进行广度优先遍历(bfs),用一个list来记录图的遍历。遍历的下一个顶点作为边的另一端顶点的子顶点,用一个数组parent[]来记录,这样便于下面树的构建。然后通过目标顶点作为根节点、数组parant、遍历结果list来构建树。图的广度优先遍历代码如下:

/** 从顶点v搜索BFS*/
public Tree bfs(int v) {List<Integer> searchOrders = new ArrayList<Integer>();int[] parent = new int[vertices.size()];for (int i = 0; i < parent.length; i++)parent[i] = -1; // 初始化parent[i]到- 1java.util.LinkedList<Integer> queue =new java.util.LinkedList<Integer>(); // list用作队列boolean[] isVisited = new boolean[vertices.size()];queue.offer(v); // 入队VisVisited[v] = true; // 标记它访问while (!queue.isEmpty()) {int u = queue.poll(); // 出队到UsearchOrders.add(u); // u 搜索for (int w : neighbors.get(u)) {if (!isVisited[w]) {queue.offer(w); // 入队 wparent[w] = u; //把遍历的下一个顶点作为一个子顶点,便于后面树的构建isVisited[w] = true; // 标记它访问}}}return new Tree(v, parent, searchOrders);}

重载树的方法Tree代码如下

  /** 树的内部类里面的抽象图形类 */public class Tree {private int root; // 树的根private int[] parent; // 存储每个顶点的父private List<Integer> searchOrders; // 高阶的搜索/** 构建具有根,父树,和搜索命令 */public Tree(int root, int[] parent, List<Integer> searchOrders) {this.root = root;this.parent = parent;this.searchOrders = searchOrders;}/** 返回树的根 */public int getRoot() {return root;}/** 返回顶点V的父节点*/public int getParent(int v) {return parent[v];}/** 返回表示搜索顺序的数组 */public List<Integer> getSearchOrders() {return searchOrders;}/** 返回的顶点数 */public int getNumberOfVerticesFound() {return searchOrders.size();}/** 从顶点索引到根的顶点的路径 */public List<V> getPath(int index) {ArrayList<V> path = new ArrayList<V>();do {path.add(vertices.get(index));index = parent[index];}while (index != -1);return path;}}

最后我们根据游戏开始硬币的状态作为顶点,从顶点索引到根的顶点的路径。代码如上代码的getpath()方法。这样我们就找到了从某个硬币状态到每个硬币都为反面的最短路径之一(但一定是最短路径)。 我们根据路径渲染GUI界面就可以了。

http://download.csdn.net/download/summerjx/10151701

数据结构-16枚硬币问题相关推荐

  1. 如何通过投掷一枚硬币产生各种概率

    一枚均值硬币(fair coin),其概率分布为 [(0,0.5),(1,0.5)][(0, 0.5), (1, 0.5)] import randomdef coin():p = random.ra ...

  2. 实验项目3———8枚硬币问题

    1. 实验题目 在 8 枚外观相同的硬币中, 有一枚是假币, 并且已知假币与真币的重量不同, 但不知 道假币与真币相比较轻还是较重.可以通过一架天平来任意比较两组硬币, 设计一个高 效的算法来检测出这 ...

  3. n枚硬币问题(找假币)

    问题描述: 在n枚外观相同的硬币中,有一枚是假币,并且已知假币与真币的重量不同,但不知道假币与真币相比较轻还是较重.可以通过一架天平来任意比较两组硬币,设计一个高效的算法来检测这枚假币. 解题思路: ...

  4. 你有没有扔过一枚硬币选择正反面?

    除了阳光没有什么可以笼罩世界 除了雨没有什么可以画出彩虹 除了雪没有什么可以洁白大地 除了风没有什么可以吹动树叶 你有没有看到自己眼中的绝望 你有没有听见痛彻心肺的哭声 你有没有感到心如花朵般枯萎 你 ...

  5. (2013.05.05)N枚硬币找1枚假币

    N枚硬币找1枚假币 ――Neicole (2013.05.05) 0. 问题描述 共有N枚硬币,一个天平,在这N枚硬币中有一枚假币,设法找出该枚假币. 1. 原理示例(减治法) 概要: 如上图所示,假 ...

  6. 12枚硬币中取1枚假币的问题

    题目描述 12个硬币中存在一个假币,不知是比真币重还是轻.现有一个天秤,要求称3次找出假币,并知其比真币重还是轻. 题解 首先将12枚硬币分3组编号分别为Ⅰ(1.2.3.4).Ⅱ(5.6.7.8).Ⅲ ...

  7. Java实现8枚硬币问题(减治法)

    1 问题描述 在8枚外观相同的硬币中,有一枚是假币,并且已知假币与真币的重量不同,但不知道假币与真币相比较轻还是较重.可以通过一架天平来任意比较两组硬币,设计一个高效的算法来检测这枚假币. 2.1 减 ...

  8. 小a和小b一起玩一个游戏,两个人一起抛掷一枚硬币,正面为H,反面为T。两个人把抛到的结果写成一个序列。如果出现HHT则小a获胜,游戏结束。如果HTT出现则小b获胜。问a获胜的概率?

    小a和小b一起玩一个游戏,两个人一起抛掷一枚硬币,正面为H,反面为T.两个人把抛到的结果写成一个序列.如果出现HHT则小a获胜,游戏结束.如果HTT出现则小b获胜.小a想问一下他获胜的概率是多少? 情 ...

  9. 腾讯2019技术岗笔试 猜硬币 众所周知,每一枚硬币都有两面,假定投掷一枚硬币,得到正面和反面的概率是一样的。小Q有一天和好朋友在玩投掷硬币的游戏,他投了n枚硬币,已知至少有p正,q反,求n枚硬币

    众所周知,每一枚硬币都有两面,假定投掷一枚硬币,得到正面和反面的概率是一样的.小Q有一天和好朋友在玩投掷硬币的游戏,他投了n枚硬币,已知至少有p正,q反,求n枚硬币正面向上的期望是多少. 分析: 1. ...

最新文章

  1. hook什么意思_这是什么骚代码!
  2. idle显示出错信息 python_原来学Python最好的书是这一本?它在bookauthority里排名第三...
  3. C#-求int数组中连续偶数列的个数
  4. [重要公告] 关于禁止发布Windows系统及非法激活软件的通知
  5. linux目录跳转快捷方式——z武器
  6. 调整 Jupyter Notebook 的代码字体
  7. ajaxSubmit、ajaxSubmit添加额外数据
  8. 快检员计算机知识,计算机检验员(初/中/高级/技师/高技)
  9. 输出101到200的素数python_python 判断101-200之间有多少个素数,并输出所有素数。...
  10. 音频ncm格式文件转mp3,ncm转mp3
  11. 计算机里一共录入多少个汉字,计算机操作员之汉字输入方法
  12. 一名优秀的测试工程师,应具备那些能力
  13. STC51控制的超声波HY-SRF05测距、红外接收小车代码
  14. mysql如何查询前几天_sql语句查询mysql怎么取前几天的数据
  15. 【大数据】医疗大数据“九大业务应用”相关研究
  16. 802.1x EAP(证书)、PEAP(证书、EAP-MSCHAP v2)认证配置(NPS、组策略)
  17. matlab中函数参数和变量作用域
  18. Canvas transform浅析
  19. 32位计算机百度盘,【安装包】正版office_2010(win7专用【32位】)
  20. 2020中国产业区块链名录:致敬在产业区块链领域发力的公司(机构)(持续补充)

热门文章

  1. Google天气预报API
  2. MATLAB显示剪切板不可用,电脑剪切板不能正常启动或者使用。
  3. win10如何配置maven仓库
  4. 32*4段 超低功耗LCD液晶显示驱动IC-VKL128 LQFP44,适用水表/传感器/热能表/压力表/测厚仪等,工作电流约7.5微安
  5. DAO 为什么难以实现问责制的去中心化
  6. 三维家可以导入别人的方案吗_怎么把su模型导入三维家
  7. 技术小品文(一)字符串放在哪里?
  8. 2020寒假集训排位赛 Cow Gymnastics 题解(思维)
  9. Rust机器学习之Linfa
  10. 【CentOS 7.0】配置免费阿里云Docker镜像加速器