- 浏览: 122539 次
- 性别:
- 来自: 上海
最新评论
图中代权的最小树的问题如下:
如果N个城市之间(图中的顶点)要修公路(图中的边)以使所有的城市联通,求怎样修可以使得公路的总长最小?
以上问题中的N个城市之间可以用图中的顶点表示,公路可以图中的边表示,公路的长度用边长表示,公路是双向的。问题就转换为在有N个顶点中的双向代权图中求得一个最小树。这里的代权指的边的长度,这与以前的不代权的最小树生成算法有很大的区别。
算法描述如下:
任选一个节点开始,将该节点标志为已访问过的节点。也就是最小树中的节点。并设置为当前节点。
1 寻找此访问节点的所有的邻接顶点,将边置入优先队列。邻接顶点不考虑已标志为访问的节点,因为它已在结果中。
2 重复 步骤1 直到没有新的边被发现。此时在所有发现的边中找到最小的边,将其终点顶点标志为已访问,放入最小树中。并设置为当前节点
3 重复 步骤 1,2,直到边的队列中没有多余的边,算法结束。
注意:这里的优先级队列是个修正过的优先级队列,每次向该队列中加入一条新边时后,会检查是否有与新边终点相同的第二条边的存在,如果有,则删除边长较大的边。因为如果存在这样的边说明,有两条从已访问过节点到相同目标节点的路径存在,如果这样的话只用保留最小的那条边即可。
这里的图采用Graph 图-邻接矩阵法 表示。
算法实际上是作如下操作:
先准备好一个优先级队列,里面以边长为关键值存放边,边的起点表示已被访问过的节点,而边的终点表示未访问的节点。将某节点标志为访问过节点。开始算法。
寻找该访问过节点的所有边,并记录边长,放入边优先级队列中;
找到所有从已访问过的节点到未访问节点的边中的最小边;
将最小边连接的顶点设置为访问过,重复以上过程,直到所有节点都变成已访问。
主要的类如下:
Edge:记载边
PriorityQ:修正后的优先级队列
Vertex:顶点
Gragh:图
Gragh.mstw():最小树生成算法
Gragh.main():提供简单测试
代码如下:
class Edge { //边:记载起始,与终止节点的下标,以及边的长度 private int from; private int to; private int length; Edge(int from, int to, int length) { this.from = from; this.to = to; this.length = length; } int from() { return from; } //起点 int to() { return to; } //终点 int length() { return length; } //边长 } /** * 修正过的优先级队列,边长最小的队列的头部,且队列中不会出现到达同一个节点 * 的两条边,如果添加新边到队列中时出现这种情况,则队列自动删除边长较大的边。 */ class PriorityQ { private Edge[] edges; private int pos = -1; PriorityQ(int size) { //创建指定长度的优先级队列 edges = new Edge[size]; } void add(Edge edge) { //添加新边到队列中 assert pos < edges.length; //按照边长将新边插入队列中合适的位置 int index = ++pos; while(index > 0 && edges[index-1].length() < edge.length()) { edges[index] = edges[index-1]; index--; } edges[index] = edge; //在队列中检查是否有与新边终点相同的边,如果有则作修正处理 removeDuplicate(edge.to()); } private void removeDuplicate(int to) { //根据终点在队列中查找重复的边,并处理 int count = 0; //记录找到同样终点的边的个数 for(int index=pos; index>-1; index--) { if(edges[index].to() == to) count++; if(count == 2) { //将第二次找到的边作删除处理 for(int i=index; i<pos; i++) edges[i] = edges[i+1]; pos--; return; } } } Edge remove() { //移出并返回最小的边 return edges[pos--]; } boolean isEmpty() { return pos == -1; } } class Vertex { //顶点类,记载顶点的value,并可以记录是否访问过 private Object value; private boolean isVisited; Vertex(Object value) { this.value = value; } void visit() { isVisited = true; } void clean() { isVisited = false; } boolean isVisited() { return isVisited; } Object value() { return value; } @Override public String toString() { return "" + value; } } class Graph { //无向图,记录顶点,顶点之间的边,以及边的长度 private Vertex[] vertexs; private int[][] adjMat; private int length = 0; private static final int INFINITY = -1; //表示不存在边时的状态 Graph(int size) { //初始化图的数据结构,包括顶点,边,边都置为不存在 vertexs = new Vertex[size]; adjMat = new int[size][size]; for(int i=0; i<size; i++) for(int j=0; j<size; j++) adjMat[i][j] = INFINITY; } void add(Object value) { //添加新的顶点 assert length <= vertexs.length; vertexs[length++] = new Vertex(value); } void connect(int from, int to, int length) { //顶点之间添加边,指定边长 adjMat[from][to] = length; adjMat[to][from] = length; } /** * 在邻接矩阵中,查找指定顶点的未访问过邻居顶点 * 如果从从起点到终点的边存在,且没有标志为访问,则返回终点下标。 * @param offset 指定开始查找的列 * @param index 指定查找的行 */ int findNeighbor(int index,int offset) { // for(int i=offset; i<length; i++) { if(adjMat[index][i] != INFINITY && !vertexs[i].isVisited()) return i; } return -1; } Edge[] mstw(int index) { //最小树生成算法,index为开始的坐标 assert vertexs[index] != null; Edge[] result = new Edge[length-1]; //生成结果数组,边的数量为顶点数量-1 PriorityQ q = new PriorityQ(length); //准备优先级队列 int pos = -1; vertexs[index].visit(); //将起始顶点标志为访问过的 while(true) { //寻找已访问过的节点与未访问过节点之间的边,并加入优先级队列 int i = -1; while((i = findNeighbor(index,i+1)) != -1) { Edge e = new Edge(index,i,adjMat[index][i]); q.add(e); } if(q.isEmpty()) break; //如果队列中没有多余的边,算法结束 //在队列中找到边长最短的边,将终点节点标志为访问过,并将此边从队列中删除 result[++pos] = q.remove(); index = result[pos].to(); //以新的终点作为起点,准备下一次迭代 vertexs[index].visit(); } clean(); //将所有访问标志复位 return result; } void clean() { for(Vertex v: vertexs) if(v != null)v.clean(); } Object get(int index) { return vertexs[index]; } public static void main(String[] args) { //测试 Graph g = new Graph(20); //添加顶点 g.add('a'); g.add('b'); g.add('c'); g.add('d'); g.add('e'); g.add('f'); //连接顶点,并指明边长 g.connect(0,1,6); g.connect(0,3,4); g.connect(1,2,10); g.connect(1,3,7); g.connect(1,4,7); g.connect(2,3,8); g.connect(2,4,5); g.connect(2,5,6); g.connect(3,4,12); g.connect(4,5,7); int sum = 0; //记录总边长 for(Edge e: g.mstw(4)) { //以任意顶点开始生成最小树 System.out.println(g.get(e.from()) + " -- " + g.get(e.to()) + " : " + e.length()); sum += e.length(); } System.out.println(sum); } }
评论
如果所有的边的端点必须是顶点(城市),这样的公路网络只会在偶然的情况下是总长度最小的。
发表评论
-
图-最小路径
2008-05-28 00:40 2811这里使用的是Dijkstra来计算最短路径。事实上Dijkst ... -
图-每一对端点间的最小距离
2008-05-26 00:24 2191与传递闭包问题 非常相似的一个问题是,能不能给出一个矩阵,根据 ... -
图-传递闭包
2008-05-23 07:57 4855图的传递闭包是指修正后的邻接矩阵表示的图。(见Graph 图- ... -
图-拓扑排序
2008-05-22 00:54 2661当每个任务有前后置关系时,需要找到一种满足前后置关系的路线,将 ... -
图-最小树
2008-05-21 00:08 1894如果一个图中所有点都是联通的,求最小树可以将图遍历完成,这里的 ... -
图-广度优先遍历
2008-05-20 00:11 4316这里的图的广度优先遍历算法利用了队来实现。 图的深度遍历原则: ... -
图-深度优先遍历
2008-05-19 00:14 4518这里的图的深度优先算法利用了栈来实现。 图的深度遍历原则: 1 ... -
递归-全排列
2008-05-16 21:00 4185将指定数组全排列打印,此处使用递归算法。 其核心是,轮流将数组 ... -
递归-组合
2008-05-15 01:12 2660求指定数据的组合,这里的指定数据用一个数组模拟所有可以选择的数 ... -
递归-背包问题
2008-05-14 00:10 4811背包问题有许多种形式,最简单的背包问题形式:现在有一堆石头,( ... -
递归-汉诺塔
2008-05-13 00:13 1873汉诺塔问题。 这里顺便可以求出一共需要搬运的次数。 以下是汉诺 ... -
递归-求幂
2008-05-12 00:08 3036计算幂,n^m,其中n为底数,m为幂 当m取值比较大时如果采用 ... -
递归-二分法查找
2008-05-11 02:03 3923二分法查找是建立在针对有序数组的查找,这里使用的是递归的算法, ... -
递归-阶乘
2008-05-10 15:45 1977用递归算法求得阶乘。 阶乘用迭代可以更有效的求得。这里只是演示 ... -
排序-堆
2008-05-08 08:34 1752堆排序的时间效率与快速排序 相同,也为O(n * log n) ... -
排序-基数
2008-05-07 00:24 1274基数排序是种与众不同的排序方法,它不是基于比较和交换。其理论时 ... -
排序-快速
2008-05-06 00:39 1457快速排序是通用排序中 ... -
排序-希尔
2008-05-05 00:17 1631插入排序 对基本有序的数组效果非常好,但是对于通常情况则表现一 ... -
排序-归并
2008-05-03 17:57 1652归并排序的时间效率为O(n * log n) 算法假设两个已有 ... -
排序-插入
2008-05-02 23:30 1476插入排序算法比冒泡 和选择 略微复杂些,但效率好些。 插入排序 ...
相关推荐
"最小树"问题通常指的是在图论中的"最小生成树"问题,这是一个经典的图优化问题。在给定的网络中,各个城市之间由边相连,每条边代表两个城市之间的距离或成本。最小生成树的目标是找到这样一个树形子集,它包含图中...
scratch编程项目源代码文件案例素材-小树长大.zip scratch编程项目源代码文件案例素材-小树长大.zip scratch编程项目源代码文件案例素材-小树长大.zip scratch编程项目源代码文件案例素材-小树长大.zip scratch...
标题中的“小树卡通PPT背景图片.zip”表明这是一个包含卡通风格的小树图案,用于PowerPoint演示文稿的背景图片的压缩文件。这种类型的资源通常用于制作儿童教育、环保主题或者轻松愉快氛围的PPT,以增加视觉吸引力并...
最小树算法是图论中的一个经典问题,主要应用于网络优化,如通信网络设计、电力系统规划、运输问题等。在本案例中,我们有一个名为"mintreek.rar_最小树"的压缩包,其中包含了一个名为"mintreek.m"的MATLAB文件,这...
最小树代码通常指的是在图论中的最小生成树问题,但在这个场景中,描述和标签提到了"初学者算法"和"C++",并且主要内容涉及的是KMP算法,这是一个字符串匹配的算法,而非构建最小生成树的方法。因此,我们将重点讨论...
最小树问题通常指的是在图论中的最小生成树问题,目标是找到一个加权无向图的边子集,这些边连接了所有的顶点,并且使得子集的总权重最小。这个问题有多种解决方案,其中一种是Prim算法或Kruskal算法,但这里我们...
它是关于最小树与最小树形图 方面的相关资料。。。
运筹学课程教学设计2-Tree and minimal tree of graph树与图的最小树-英文版.docx
大班社会教案-保护小树.docx
大班社会教案-爱护小树.docx
寻找最小树(minimal tree)是图论中的一个重要问题,这通常指的是在保持所有顶点连接性的前提下,边的总权重尽可能小的生成树。这个问题在实际应用中非常常见,例如在构建通信网络、交通路线规划或者最小成本设计...
**铅笔工具**:铅笔工具是画图程序中最基础也是最常用的工具之一。它允许用户以自由手绘的方式绘制线条或形状,适合用来勾勒图形的轮廓。在微软画图程序中,铅笔工具通常位于工具栏的显眼位置,其图标为一支铅笔。 ...
通过观察和排列描绘小树成长过程的图片,孩子们可以了解到生物生长的基本规律,并尝试用语言描述出来。 活动目标主要有两个方面:首先,孩子们需要能够仔细观察图片,发现画面之间的变化和联系,学习按照图片的顺序...
PPT模板-粉色小树PPT模板.dpt
任意维度欧几里得斯坦纳最小树的启发式欧几里得斯坦纳最小树 (ESTP) 问题寻求一个总边长最小的网络,该网络跨越一组 n 个端点,同时允许插入额外的点(斯坦纳点)以减少网络的总长度。 该软件使用启发式方法为任何...
在“小树成长”的功能中,用户可以通过一系列操作来“照顾”虚拟的小树,例如浇水、施肥等,随着用户的参与度增加,小树会逐渐长大。这个过程可以设计成与用户互动的挑战,例如设置时间间隔,鼓励用户每天回访。同时...
Kruskal生成最小树算法,可以画出最小树
根据给定的文件信息,我们可以总结出以下与C++图的深度优先遍历(Depth-First Search, DFS)、广度优先遍历(Breadth-First Search, BFS)以及最小生成树(Minimum Spanning Tree, MST)相关的知识点: ### C++中的...