热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

DS图—最小生成树(待验证)

题解一.primprim算法的时间复杂度为O(n^2),与网中的边数无关,适用于求边稠密的网的最小生成树。prim算法中每次都要找一端在U中一端在V

题解


一.prim

  1. prim算法的时间复杂度为O(n^2),与网中的边数无关,适用于求边稠密的网的最小生成树。
  2. prim算法中每次都要找一端在U中一端在V-U中的边中权值最小的边。这里U的实现可以通过设置一个visit数组,如果在U里面就置为1,而不是为U重新创建一个顶点集。找权值最小就可以先设置大初值变量minweight,然后遍历所有符合条件的边,如果权值比minweight小就赋给minweight。
  3. prim循环结束的条件是U等于V,对应到算法就是visit数组全为1。这里visit数组是否全为1不能作为判断条件直接写进while头,所以可以为这段代码单独开一个isOver函数,然后while头中用该函数就好了。
  4. prim要求输出图最小生成树的边信息,所以这里需要对边进行存储。边一共包含三个数据,start顶点,end顶点,边的权值,对其存储可以通过结构体数组、三个普通数组结合、三个队列或三个栈、邻接表或邻接矩阵,前两者的缺点在于存入和输出时需要计数,而用栈和队列就不需要计数,这里采用结构体数组来存(注意startvex和endvex是代表对应顶点的下标,而不是其内容,因为下标操作起来更方便一些)。
  5. 代码中Index函数的作用是根据传入数据的内容,返回其在数组中对应的下标。对于数组而言,知道下标很容易得到数组值,而知道值要得到下标需要遍历整个数组,并且常常用到这个操作,所以干脆给数组定义一个Index函数。
  6. 在网里面邻接矩阵的值不再是0和1,而是将图中的1变为了权值,而在prim中需要选择权值最小的边,如果还是将没有边用0表示的话就会对其产生干扰,所以这里初始化网用无穷。

二.kruskal

  1. kruskal算法的时间复杂度为O(eloge),e为网中的边数,适用于求解边稀疏的网的最小生成树。
  2. kruskal算法中每次需要选择权值最小的边,并且之前选择过的边不参加选择。其的实现可以通过用一个结构体数组来存无向网中的所有边,并且以边权值的升序顺序存储,这样每次就只要向后遍历该数组取边就可以了。实现权值升序可以先正常存,然后针对其权值来个冒泡排序就可以了。
  3. 每次选取了权值最小的边之后需要判断其的start顶点和end顶点是否位于同一连通分量。这里可以将位于同一连通分量的顶点视为一棵树,它们有同一个根节点,因此是否在同一连通分量就转化为顶点的根节点是否相同。根节点的实现可以设置一个parent数组,初始每个顶点的parent都置为-1代表它们都是根节点(由于顶点下标0开始,-1代表为根节点避免与0冲突)。这里需要对顶点进行找根操作,可以定义一个FindRoot函数(不断迭代到parent为-1)。如果start和end顶点根节点不同,就可以输出这条边了(这里最小生成树中的边不需要存储,得到后直接输出就好了),然后让end顶点的parent值为start顶点下标就完成了统一根节点。
  4. 这里结束函数的条件就在于是否找到并输出了vexnum-1条边。可以在对应的程序块中添加一个控制变量,每次执行该段就++,当等于vexnum-1就return退出函数。

题目

问题 A: DS图—最小生成树
时间限制: 1 Sec 内存限制: 128 MB
提交: 1035 解决: 395
[提交][状态][讨论版]
题目描述
根据输入创建无向网。分别用Prim算法和Kruskal算法构建最小生成树。(假设:输入数据的最小生成树唯一。)输入
顶点数nn个顶点边数mm条边信息,格式为:顶点1 顶点2 权值Prim算法的起点v输出
输出最小生成树的权值之和对两种算法,按树的生长顺序,输出边信息(Kruskal中边顶点按数组序号升序输出)样例输入
6
v1 v2 v3 v4 v5 v6
10
v1 v2 6
v1 v3 1
v1 v4 5
v2 v3 5
v2 v5 3
v3 v4 5
v3 v5 6
v3 v6 4
v4 v6 2
v5 v6 6
v1
样例输出
15
prim:
v1 v3 1
v3 v6 4
v6 v4 2
v3 v2 5
v2 v5 3
kruskal:
v1 v3 1
v4 v6 2
v2 v5 3
v3 v6 4
v2 v3 5

代码块

#include
using namespace std;class Edge
{int weight;int startvex, endvex;
public:Edge(){}~Edge(){}friend class Graph;
};class Graph
{
private:int vexnum;int edgenum;string *vertex;int **matrix;bool *visit;Edge *edge1;int *parent;Edge *edge2;int Index(string str);bool IsOver();int FindRoot(int vex);
public:Graph();~Graph();void MinSpanTree_Prim(string vex);void MinSpanTree_Kruskal();
};Graph::Graph()
{int i, j, weight;string startvex, endvex;//这里对顶点的表示用string而不是下标是因为输入或输出的形式所迫&#xff0c;其他情况用下标&#xff0c;这种形式想对它操作还要麻烦地用Index函数定位到下标。cin>>vexnum;vertex &#61; new string[vexnum];matrix &#61; new int*[vexnum];visit &#61; new bool[vexnum];edge1 &#61; new Edge[vexnum-1];parent &#61; new int[vexnum];for(i&#61;0; i<vexnum; i&#43;&#43;){cin>>vertex[i];matrix[i] &#61; new int[vexnum];visit[i] &#61; false;parent[i] &#61; -1;for(j&#61;0; j<vexnum; j&#43;&#43;)matrix[i][j] &#61; 99999;//用无穷初始化邻接矩阵}cin>>edgenum;edge2 &#61; new Edge[edgenum];for(i&#61;0; i<edgenum; i&#43;&#43;){cin>>startvex>>endvex>>weight;edge2[i].endvex &#61; Index(endvex);edge2[i].startvex &#61; Index(startvex);edge2[i].weight &#61; weight;matrix[Index(startvex)][Index(endvex)] &#61; weight;matrix[Index(endvex)][Index(startvex)] &#61; weight;//在无向图中注意要把对称的边也初始化。}Edge temp;for(i&#61;0; i<edgenum-1; i&#43;&#43;){//针对结构体中weight进行冒泡排序for(j&#61;0; j<edgenum-1-i; j&#43;&#43;){if(edge2[j].weight>edge2[j&#43;1].weight){temp &#61; edge2[j];edge2[j] &#61; edge2[j&#43;1];edge2[j&#43;1] &#61; temp;}}}
}Graph::~Graph()
{for(int i&#61;0; i<vexnum; i&#43;&#43;)delete []matrix[i];delete []vertex;delete []matrix;delete []visit;delete []edge1;delete []parent;delete []edge2;
}int Graph::Index(string str)
{for(int i&#61;0; i<vexnum; i&#43;&#43;){if(vertex[i]&#61;&#61;str)return i;}
}bool Graph::IsOver()
{for(int i&#61;0; i<vexnum; i&#43;&#43;){if(!visit[i])return false;}return true;
}int Graph::FindRoot(int vex)
{while(parent[vex]!&#61;-1){vex &#61; parent[vex];}return vex;
}void Graph::MinSpanTree_Prim(string vex)
{int i, j, startvex, endvex;int weightsum &#61; 0, pos &#61; 0;visit[Index(vex)] &#61; true;while(!IsOver()){int minweight &#61; 99999;for(i&#61;0; i<vexnum; i&#43;&#43;){//遍历所有符合条件的边&#xff1a;先用for对所有边遍历&#xff0c;然后for里面再用if筛选符合条件的情况。if(visit[i]){for(j&#61;0; j<vexnum; j&#43;&#43;){if(!visit[j] && matrix[i][j]<minweight){minweight &#61; matrix[i][j];startvex &#61; i;endvex &#61; j;}}}}visit[endvex] &#61; true;weightsum &#43;&#61; minweight;edge1[pos].startvex &#61; startvex;edge1[pos].endvex &#61; endvex;edge1[pos].weight &#61; minweight;pos&#43;&#43;;}cout<<weightsum<<endl;cout<<"prim:"<<endl;for(i&#61;0; i<vexnum-1; i&#43;&#43;)cout<<vertex[edge1[i].startvex]<<&#39; &#39;<<vertex[edge1[i].endvex]<<&#39; &#39;<<edge1[i].weight<<endl;//注意这里的startvex和endvex只是下标&#xff0c;输出要套上顶点数组。
}void Graph::MinSpanTree_Kruskal()
{int i, vex1, vex2;int num &#61; 0;cout<<"kruskal:"<<endl;for(i&#61;0; i<edgenum; i&#43;&#43;){vex1 &#61; FindRoot(edge2[i].startvex);vex2 &#61; FindRoot(edge2[i].endvex);if(vex1!&#61;vex2){cout<<vertex[edge2[i].startvex]<<&#39; &#39;<<vertex[edge2[i].endvex]<<&#39; &#39;<<edge2[i].weight<<endl;parent[vex2] &#61; vex1;num&#43;&#43;;if(num&#61;&#61;vexnum-1)return;}}
}int main(void)
{Graph myGraph;string vex;cin>>vex;myGraph.MinSpanTree_Prim(vex);myGraph.MinSpanTree_Kruskal();return 0;
}


推荐阅读
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
author-avatar
爱是一道菜lzb
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有