实习三--求无向连通图的生成树
生成树的名词解释

生成树的名词解释生成树(Spanning Tree)是图论中的一个重要概念,用来描述在一个无向连通图中连接所有顶点的极小连通子图。
在一个无向连通图中,如果能够找到一颗包含所有顶点且边数最少的子图,那么这个子图就是该图的生成树。
生成树的概念最早由Otto Schönflies于1885年提出,并且在图论研究和实际应用中得到了广泛的运用。
生成树在电网规划、通信网络设计、计算机网络以及城市交通规划等领域都有着重要的应用价值。
生成树的定义可以用简洁的方式表述:在一个无向连通图中,生成树是保留了原图的所有顶点,但只保留了足够的边来使得这个子图连通,并且不包含任何环的一种连通子图。
换句话说,生成树是一个无向连通图中的极小连通子图,它连接了所有的顶点,并且不存在回路。
生成树具有很多重要的性质和应用。
首先,生成树的边数比原图的顶点数少一个。
这是因为生成树是一个连通子图,而且不包含任何环。
因此,生成树中的边数等于原图的顶点数减去1。
这个性质经常用于生成树的构造和推导。
其次,生成树可以用于表示图中的最小连接网络。
在一个无向连通图中,如果存在多个连通子图,那么通过连接这些子图的最少的边,就可以得到一个生成树。
这个生成树可以看作是一个最小的连通网络,其中所有顶点都能够通过最短路径相互到达。
此外,生成树还可以用于网络设计和优化问题。
在电网规划、通信网络设计和计算机网络中,生成树常常被用于实现信息的传输和路由的优化。
通过构造合适的生成树,可以使得信息的传输路径更加简洁和高效。
生成树有多种构造算法,其中最常用的是Prim算法和Kruskal算法。
Prim算法是一种贪心算法,它从一个任意选定的顶点开始,逐步构建生成树。
具体地,Prim算法每次选择与已有的生成树连接边权值最小的顶点,并将其加入生成树。
重复这个过程,直到生成树包含了所有的顶点。
Kruskal算法是一种基于边的方法,它首先将图中的边按照权值从小到大排序,然后依次将边加入生成树,直到生成树包含了所有的顶点为止。
无向连通图的生成树kruskal

采用kruskal(克鲁斯卡尔)算法求无向连通网图的一棵最小生成树。
#include<iostream>using namespace std;const int MaxSize=6; // 顶点数const int m=9; //边数int vertexNum, arcNum; //顶点数和边数char vertex[MaxSize]; //顶点数组int parent[MaxSize];struct EdgeType{int from, to;int weight;};EdgeType edge[m];void edgesz(char a[], int n, int e){int i,j,k,w;vertexNum=n; arcNum=e;for (i=0; i<vertexNum; i++) vertex[i]=a[i];for (k=0; k<arcNum; k++) //依次输入每一条边{cin>>i>>j>>w; //边依附的两个顶点的序号及权值edge[k].from=i;edge[k].to=j;edge[k].weight=w;}}int FindRoot(int parent[], int v){int t;t=v;while ( parent[t]>-1) t=parent[t];return t;}void DubbleSort(EdgeType r[],int n){int exchange,bound,j,k;exchange=n-1; //第一趟的区间为1-- nwhile(exchange) //当还未完全有序{ bound=exchange; //传递本趟最后交换位置exchange=0;for(j=0;j<bound;j++) //一趟扫描if (r[j].weight>r[j+1].weight){k=r[j].from;r[j].from=r[j+1].from;r[j+1].from=k;k=r[j].to;r[j].to=r[j+1].to;r[j+1].to=k;k=r[j].weight;r[j].weight=r[j+1].weight;r[j+1].weight=k;exchange=j; } //记录交换位置}}//kruskal(克鲁斯卡尔)算法int main(){int i;char a[MaxSize];cout <<"输入"<<MaxSize<<"个顶点数据:"<<endl;for (i=0;i<MaxSize;i++) cin >>a[i];cout <<"依次输入"<<m<<"条边的每一条边两个顶点的序号及权值:"<<endl;edgesz(a, MaxSize, m);DubbleSort(edge,m);cout <<"无向连通图的(Kruskal)生成树为:"<<endl;Kruskal();cout << endl;return 0;}。
最小生成树求解无向的最小连接子

最小生成树求解无向的最小连接子最小生成树(Minimum Spanning Tree)是图论中的一个概念,指的是在一个联通图中,找出一个子集,使得所有节点都能连接起来,并且边的权值之和最小。
在实际应用中,最小生成树常用于优化网络通信、城市规划、电力传输等问题。
一、什么是最小生成树在图论中,最小生成树是指在一个具有n个顶点的联通图中,选择n-1条边,将n个顶点相互连接,形成具有最小总权值的树形结构。
这里的总权值是指选择的n-1条边的权值之和。
二、Kruskal算法Kruskal算法是一种经典的求解最小生成树问题的算法。
其基本思想是先将所有边按照权值从小到大进行排序,然后依次加入到最小生成树中,直到满足n-1条边的条件。
具体步骤如下:1. 创建一个空的最小生成树集合,初始化为0条边。
2. 将图中的所有边按照权值从小到大排序。
3. 依次遍历排序后的边,如果该边的两个顶点不在同一个连通分量中,则将该边加入到最小生成树集合中,并合并两个连通分量。
4. 重复步骤3,直到最小生成树集合中边的数量达到n-1条。
三、Prim算法Prim算法是另一种常用的最小生成树算法,其基本思想是从一个顶点开始,每次选择一个和当前最小生成树集合相邻的最小权值边,并将该边的另一个顶点加入到最小生成树集合中。
具体步骤如下:1. 创建一个空的最小生成树集合,初始化为0条边。
2. 随机选择一个顶点作为起始点,将其加入到最小生成树集合中。
3. 每次从最小生成树集合中选出一个顶点,遍历其邻接边,选择权值最小的边,并将该边的另一个顶点加入到最小生成树集合中。
4. 重复步骤3,直到最小生成树集合中顶点的数量达到n个。
四、应用示例假设有一个无向图如下所示:```A---4---B/ \ / \2 3 6 8/ \ \C---9---D---5--E```我们可以使用Kruskal算法或Prim算法求解最小生成树。
使用Kruskal算法的步骤如下:1. 将所有边按照权值从小到大排序:AC, AB, AD, BC, BD, BE, CD, DE。
无向连通图的生成树

#include<stdio.h>#include<stdlib.h>#define M 20#define MAX 20typedef struct{int begin;int end;int weight;}edge;typedef struct{int adj;int weight;}AdjMatrix[MAX][MAX];typedef struct{AdjMatrix arc;int vexnum, arcnum;}MGraph;void CreatGraph(MGraph *);//函数申明void sort(edge* ,MGraph *);void MiniSpanTree(MGraph *);int Find(int *, int );void Swapn(edge *, int, int);void CreatGraph(MGraph *G)//构件图{int i, j,n, m;printf("请输入边数和顶点数:");scanf("%d %d",&G->arcnum,&G->vexnum);for (i = 1; i <= G->vexnum; i++)//初始化图{for ( j = 1; j <= G->vexnum; j++){G->arc[i][j].adj = G->arc[j][i].adj = 0;}for ( i = 1; i <= G->arcnum; i++)//输入边和权值{printf("\n请输入有边的2个顶点");scanf("%d %d",&n,&m);while(n < 0 || n > G->vexnum || m < 0 || n > G->vexnum) {printf("输入的数字不符合要求请重新输入:");scanf("%d%d",&n,&m);}G->arc[n][m].adj = G->arc[m][n].adj = 1;getchar();printf("\n请输入%d与%d之间的权值:", n, m);scanf("%d",&G->arc[n][m].weight);}printf("邻接矩阵为:\n");for ( i = 1; i <= G->vexnum; i++){for ( j = 1; j <= G->vexnum; j++){printf("%d ",G->arc[i][j].adj);}printf("\n");}}void sort(edge edges[],MGraph *G)//对权值进行排序{int i, j;for ( i = 1; i < G->arcnum; i++){for ( j = i + 1; j <= G->arcnum; j++){if (edges[i].weight > edges[j].weight){Swapn(edges, i, j);}}}printf("权排序之后的为:\n");for (i = 1; i < G->arcnum; i++){printf("<< %d, %d >> %d\n", edges[i].begin, edges[i].end, edges[i].weight); }}void Swapn(edge *edges,int i, int j)//交换权值以及头和尾{int temp;temp = edges[i].begin;edges[i].begin = edges[j].begin;edges[j].begin = temp;temp = edges[i].end;edges[i].end = edges[j].end;edges[j].end = temp;temp = edges[i].weight;edges[i].weight = edges[j].weight;edges[j].weight = temp;}void MiniSpanTree(MGraph *G)//生成最小生成树{int i, j, n, m;int k = 1;int parent[M];edge edges[M];for ( i = 1; i < G->vexnum; i++){for (j = i + 1; j <= G->vexnum; j++){if (G->arc[i][j].adj == 1){edges[k].begin = i;edges[k].end = j;edges[k].weight = G->arc[i][j].weight;k++;}}}sort(edges, G);for (i = 1; i <= G->arcnum; i++){parent[i] = 0;}printf("最小生成树为:\n");for (i = 1; i <= G->arcnum; i++)//核心部分{n = Find(parent, edges[i].begin);m = Find(parent, edges[i].end);if (n != m){parent[n] = m;printf("<< %d, %d >> %d\n", edges[i].begin, edges[i].end, edges[i].weight); }}}int Find(int *parent, int f)//找尾{while ( parent[f] > 0){f = parent[f];}return f;}int main(void)//主函数{MGraph *G;G = (MGraph*)malloc(sizeof(MGraph));if (G == NULL){printf("memory allcation failed,goodbye");exit(1);}CreatGraph(G);MiniSpanTree(G);system("pause"); return 0;}。
无向连通图的生成树个数

⽆向连通图的⽣成树个数我们知道,每个⽆向连通图都会有⾃⼰的⽣成树。
但是⼤家更熟悉的,是⽆向图的最⼩⽣成树(MST)算法。
本⽂旨在讨论计算⽆向连通图的⽣成树个数的时间复杂度为O(n3)的⽅法。
另外⼀种时间效率⾼的递推式⽅法的讲解在⽂末附有链接。
我们可以利⽤矩阵在O(n3)的时间内求出⽆向连通图的⽣成树个数。
对于⼀个⽆向连通图,我们可以根据以下规则列出⼀个矩阵M:1. 主对⾓线上的值M(i,i)为i节点的度。
2. a[i,j]的值为点i到点j的平⾏边的条数的相反数。
显然,如果i,j不连通,M(i,j)=0。
通过这样的规则,⼀个矩阵就在O(n2)的时间内建⽴起来。
以图1为例。
这样,我们就得到了矩阵M:参考代码(init):beginfillchar(ma,sizeof(ma),0);readln(n,m);for i:=1 to n dofor j:=1 to n dobeginread(x);if x=1 thenbeginma[i,i]:=ma[i,i]+1;ma[i,j]:=-1;end;end;end.恩,有了这个矩阵有什么⽤呢?【定理】删除矩阵中任意⼀个节点的信息,求出剩下的(n-1)*(n-1)矩阵的⾏列式的值,此值即为这个⽆向连通图的⽣成树个数。
定理的证明在这⾥不再赘述(其实我也不会,知道怎么证明⼜有什么⽤呢可以⽤数学归纳法证明),如果想知道详细的证明过程,可以参阅⽂末所附的参考⽂献,或者在⽹上查阅。
经过删除操作,我们得到如下的矩阵M’:可是,⾏列式的值怎么求呢?我们知道⾏列式值的⼿⼯求法是经过将⾏列式降阶,通过如下的定理求得:【定理】三阶⾏列式D= 的值等于它任意⼀⾏(列)的所有元素与它们对应的代数余⼦式乘积之和。
即:⽤等式表⽰为:当阶数很⾼,这种⽅法由于要递归、压栈,不但占⽤⼤量内存,⽽且代码复杂度很⾼(现在我还没有打出来过 *.*||)。
在这⾥,我们⽤⾼斯消元的思想将⾏列式转化成⼀个下三⾓⾏列式,运⽤以下性质即可求出⾏列式的值。
生成树实验报告

一、实验目的1. 理解生成树的概念和作用;2. 掌握Prim算法和Kruskal算法实现生成树的方法;3. 分析算法的时间复杂度和空间复杂度;4. 提高算法设计与分析能力。
二、实验原理生成树(Spanning Tree)是一个无向图的所有顶点构成的一棵树,且该树包含了原图的所有顶点。
生成树在计算机网络、电路设计等领域具有广泛的应用。
在无向图中,如果任意两个顶点之间都存在路径,则称该图是连通的。
对于连通图,一定存在一棵生成树。
Prim算法和Kruskal算法是两种常见的生成树算法,它们分别采用贪心策略和最小生成树算法实现。
三、实验内容1. Prim算法实现生成树(1)初始化:设置一个数组来记录每个顶点与当前生成树的连接情况,以及一个数组来记录每个顶点到生成树的距离。
(2)选择一个顶点作为起始顶点,将其距离设置为0,其他顶点距离设置为无穷大。
(3)在当前生成树上选择距离最小的顶点,将其加入生成树,并将该顶点与其他顶点的距离更新。
(4)重复步骤(3),直到所有顶点都被加入生成树。
2. Kruskal算法实现生成树(1)将所有边按照权值从小到大排序。
(2)创建一个并查集,用于判断两个顶点是否属于同一个集合。
(3)遍历排序后的边,对于每条边,判断其两个顶点是否属于同一个集合:(a)如果属于同一个集合,则跳过该边;(b)如果不属于同一个集合,则将这条边加入生成树,并将两个顶点所属的集合合并。
(4)重复步骤(3),直到生成树包含所有顶点。
四、实验步骤1. 创建一个无向图,包含若干顶点和边。
2. 使用Prim算法实现生成树,记录算法运行时间。
3. 使用Kruskal算法实现生成树,记录算法运行时间。
4. 分析两种算法的时间复杂度和空间复杂度。
五、实验结果与分析1. Prim算法实现生成树(1)顶点集合:V = {A, B, C, D, E, F}(2)边集合:E = {(A, B, 1), (A, C, 3), (A, D, 2), (B, C, 2), (B, D, 2), (C, D, 1), (C, E, 4), (D, E, 3), (D, F, 2), (E, F, 1)}(3)Prim算法运行时间:0.001秒2. Kruskal算法实现生成树(1)顶点集合:V = {A, B, C, D, E, F}(2)边集合:E = {(A, B, 1), (A, C, 3), (A, D, 2), (B, C, 2), (B, D, 2), (C, D, 1), (C, E, 4), (D, E, 3), (D, F, 2), (E, F, 1)}(3)Kruskal算法运行时间:0.001秒通过实验,我们可以得出以下结论:1. Prim算法和Kruskal算法均可以有效地实现生成树,且在时间复杂度和空间复杂度上表现良好。
生成树原理范文

生成树原理范文生成树(Spanning Tree)是指在一个连通图中选择一些边来构建一颗无环的树,使得这颗树包含了图的所有顶点。
生成树的概念很重要,因为它在网络设计、通信协议、电力传输等领域具有广泛的应用。
生成树原理是指生成树的选择原则和生成过程的基本思想。
本文将详细介绍生成树的原理。
生成树的选择原则:1.连通性:生成树必须能够覆盖原图中的所有顶点,即生成树必须是连通的。
如果原图不连通,则不存在生成树。
2.无环性:生成树不能包含环,即生成树必须是无环的。
否则,树将变成网状结构。
3.最小权重:如果在原图的边上存在权重,生成树应选择边的权重之和最小的方案。
这样可以确保生成树是最优的。
生成树的实现方法有多种,下面介绍两种常用的方法:1. 普里姆算法(Prim's algorithm):普里姆算法是一种贪心算法,从一个起始顶点开始,逐步添加与当前生成树连接的最短权重边,直到生成树包含所有顶点为止。
具体步骤如下:(1)选择一个起点加入生成树;(2)在生成树与非生成树的边中找到权重最小的一条边,并将其加入生成树;(3)重复上述步骤直到生成树包含所有顶点。
普里姆算法的关键在于如何选择生成树与非生成树之间的边,可以通过维护两个集合来实现:一个集合表示生成树的顶点,一个集合表示非生成树的顶点。
每次从非生成树中选择一条权重最小的边,并将其连接的顶点加入生成树的集合中。
2. 克鲁斯卡尔算法(Kruskal's algorithm):克鲁斯卡尔算法也是一种贪心算法,它首先将每个顶点看作一个独立的生成树,然后逐步合并生成树,直到只剩下一个生成树为止。
具体步骤如下:(1)将原图中所有边按权重从小到大排序;(2)依次选择权重最小的边,若该边连接的两个顶点属于不同的生成树,则将这两个生成树合并为一棵生成树;(3)重复上述步骤直到生成树只剩下一个。
克鲁斯卡尔算法的关键在于如何判断两个顶点是否属于同一个生成树,可以通过并查集等数据结构来实现。
无向树及生成树

2m=2(n1)=51+21+31+4(n7)
解出n=8, 4度顶点为1个.
T的度数列为1,1,1,1,1,2,3,4
有3棵非同构的无向树
生成树
生成树的存在性
定理任何无向连通图都有生成树.
证用破圈法.若图中无圈,则图本身就是自己的生成树.
否则删去圈上的任一条边,这不破坏连通性,重复进行
直到无圈为止,剩下的图是一棵生成树.
推论1设n阶无向连通图有m条边,则mn1.
推论2设n阶无向连通图有m条边,则它的生成树的余树
有mn+1条边.
基本回路与基本回路系统
定义设T是n阶m条边的无向连通图G的一棵生成
树,设e1, e2, … , emn+1为T的弦.设Cr为T添加弦er
(1)G是树(连通无回路);
(2)G中任意两个顶点之间存在惟一的路径;
(3)G中无回路且m=n1;
(4)G是连通的且m=n1;
(5)G是连通的且G中任何边均为桥;
(6)G中没有回路,但在任何两个不同的顶点之间加一条新边后所得图中有惟一的一个含新边的圈.
下次课预习要点:
有向树
根树、树根、树叶、内点、分支点
设G=<V,E,W>,将非环边按权从小到大排序:e1, e2, …, em.
(1)取e1在T中
(2)检查e2,若e2与e1不构成回路,则将e2加入T中,否则弃去e2.
(3)检查e3,…,重复进行直至得到生成树为止.
实例
例求图的一棵最小生成树
复习思考题、作业题:
设G=<V,E>是n阶m条边的无向图,则下面各命题是等价的:
生成树工作步骤

生成树工作步骤生成树是图论中的一个重要概念,它是指能够将一张无向图的所有节点遍历一遍的有向树。
在计算机科学中,生成树也是一种常见的算法,在许多应用中都有广泛的应用。
下面将介绍一下生成树的工作步骤。
1. 确定起始点生成树的第一步是要确定起始点,这是生成树的基础。
在无向图中任选一个节点作为起点,进行深度优先遍历或广度优先遍历,找到与该节点相连接的所有节点,然后将连接节点的边加入到生成树的集合中。
2. 生成树集合初始化第二步骤是生成树集合初始化。
这一步骤将起始点的边加入到生成树的集合中,并将这些加入的边的状态标记为已访问。
在这一步骤之后,生成树集合就有了起始节点以及连接节点之间的边。
3. 确定下一个要加入的边第三步骤是要确定下一个要加入的边。
在生成树中,边可以通过多种方法被加入。
最常见的方法是通过确定边权值最小的两个节点之间的边,然后将这条边加入到生成树集合中。
4. 判断新边加入后是否成环确定下一条要加入的边后,第四步骤是要判断新边加入后是否成环。
如果新边加入后形成环,那么该边就不能被加入到生成树集合中。
此时需要选择下一条边来代替当前的边,直到找到一条不会成环的边。
5. 将新边加入到生成树中当找到不会成环的边后,第五步骤是将新边加入到生成树中,并将这些加入的边的状态标记为已访问。
在这一步骤之后,生成树集合就会多出一条新的边。
6. 重复以上步骤当新的边加入到生成树中后,需要重复以上步骤,继续寻找下一条合适的边加入到生成树中。
这一过程一直持续到生成树包含了所有的节点,即已经遍历了无向图中的所有节点。
以上就是生成树的工作步骤。
通过以上的步骤,我们就可以构建出一颗覆盖了无向图所有节点的生成树。
生成树在计算机科学中有很广泛的应用,例如网络设计、电路分析和数据压缩等。
详解图的应用(最小生成树、拓扑排序、关键路径、最短路径)

详解图的应用(最小生成树、拓扑排序、关键路径、最短路径)1.最小生成树:无向连通图的所有生成树中有一棵边的权值总和最小的生成树1.1 问题背景:假设要在n个城市之间建立通信联络网,则连通n个城市只需要n—1条线路。
这时,自然会考虑这样一个问题,如何在最节省经费的前提下建立这个通信网。
在每两个城市之间都可以设置一条线路,相应地都要付出一定的经济代价。
n个城市之间,最多可能设置n(n-1)/2条线路,那么,如何在这些可能的线路中选择n-1条,以使总的耗费最少呢?1.2 分析问题(建立模型):可以用连通网来表示n个城市以及n个城市间可能设置的通信线路,其中网的顶点表示城市,边表示两城市之间的线路,赋于边的权值表示相应的代价。
对于n个顶点的连通网可以建立许多不同的生成树,每一棵生成树都可以是一个通信网。
即无向连通图的生成树不是唯一的。
连通图的一次遍历所经过的边的集合及图中所有顶点的集合就构成了该图的一棵生成树,对连通图的不同遍历,就可能得到不同的生成树。
图G5无向连通图的生成树为(a)、(b)和(c)图所示:G5G5的三棵生成树:可以证明,对于有n 个顶点的无向连通图,无论其生成树的形态如何,所有生成树中都有且仅有n-1 条边。
1.3最小生成树的定义:如果无向连通图是一个网,那么,它的所有生成树中必有一棵边的权值总和最小的生成树,我们称这棵生成树为最小生成树,简称为最小生成树。
最小生成树的性质:假设N=(V,{ E}) 是个连通网,U是顶点集合V的一个非空子集,若(u,v)是个一条具有最小权值(代价)的边,其中,则必存在一棵包含边(u,v)的最小生成树。
1.4 解决方案:两种常用的构造最小生成树的算法:普里姆(Prim)和克鲁斯卡尔(Kruskal)。
他们都利用了最小生成树的性质1.普里姆(Prim)算法:有线到点,适合边稠密。
时间复杂度O(N^2)假设G=(V,E)为连通图,其中V 为网图中所有顶点的集合,E 为网图中所有带权边的集合。
求无向连通图的最小生成树算法

求无向连通图的最小生成树算法——Prim与Kr uskal及相关优化最小生成树是图论里很重要的部分。
但是由于它属于图论所以NO IP基本不考,对于NOI又太基础,所以竞赛中出现的几率比较小,即使要考也不可能考裸的生成树算法= =最小生成树就P rim和Kr uskal两个算法,又没有多大的优化余地,所以学习起来还是很简单的。
一.Prim算法1.算法思想对于图G=(V,E),用Prim算法求最小生成树T=(S,TE)的流程如下① 初始化:设S、TE为空集,任选节点K加入S。
②选取一条权值最小的边(X,Y),其中X∈S,且not (Y∈S)即,选取一条权值最小的、连接着S中一点与S外一点的边。
将Y加入S中,边(X,Y)加入TE中重复② 直到V=S即所有G中的点都在S中,此时的T为G的最小生成树。
由此流程可见,Prim算法求最小生成树时任何时候的T都是一颗树。
2.实现显然,Prim算法的主要运行时间花在过程②的选边中。
看起来复杂度是O(VE)=O(V^3)不是么,效率也太低了吧……为了比较快速地选边,我们用两个数组lowcos t、closest动态地维护每一个点到S的最短距离。
在某一状态下,lowcost[i]表示所有与i相连且另一端点在S中的边中的权值最小值,closest[i]表示在S中且与i相连的点中与i之间距离最小的点。
显然,lowcost[i]=w(i,closest[i])。
需要注意的是两个数组记录的都是边而不是路径。
若i没有边直接连向S,则lowcos t[i]=∞。
另外,若i已在S中,则lowcos t[i]=0。
设出发点为x。
初始时对于任意k∈V,closest[k]=x,lowcost[k]=w(k,x)【w(i,j)表示i、j间的距离。
初始化时,若两点间没有边则w(i,j)赋为一个足够大的整数(如maxint),并且所有点到自身的距离赋为0,即w(i,i)=0】每一次找出lo wcost中不为0的最小值lowco st[i],然后把i加入S(即lowcos t[i]:=0),然后对于图中所有点k,若w(k,i)<lowcost[k],则把lowco st[k]赋为w(k,i),把closes t[k]赋为i。
无向树及生成树

例9.4:无向树G有2个2度结点,1个3度结点, 3个4度结点,则其1度结点数为多少?
解:由握手定理 2m=∑d(vi) 及定理9.1 n = m+1
设G有t个1顶点, 则有下列关系式 2 x 2+3+4 x 3+t =2 m =2 x(n-1) =2 x(2+1+3+t-1) 解得:t = 9
例 9.5:无向树G有8片树叶,2个3度分支点, 其余分支点均为4度,问G有多少个4度分支点? 画出其非同构的情况。
解:设G有t个4度分支点,则有下列关系式 8 x 1+2 x 3+ t x 4 =2 x(8+2+t-1) 解得:t = 2
n
则G中共有12个顶点,11条边,度数序列之 和为22, △ (Ti)=4, (Ti)=1, 度序列为: 1,1,1,1,1,1,1,1,3,3,4, 4 其非同构的图形为:
1 8
2
7
a
2
h
4
g
3 4
d
4
6
b
c
例9.8:铺设一个连接各个城市的光纤 通信网络。 (单位:万元)
f
54
8 15
12 38 28 20 60
e
30
10
25 62
a
36
38
h
40
g
45
d
48
b
c
例9.9:用Kruskal算法求下图 的最小生成树。
。 。 。
。
。
OK!
例9.10:用Kruskal算法求下图的最小生成树。 。
c b h d e
i
定义9.5 设无向连通带权图G=<V,E,W>,T是G的一 棵生成树,T的各边权之和称为T的权,记作 W(T)。G的所有生成树中权最小的生成树称为 G的最小生成树。 求最小生成树的算法很多,我们只介绍避 圈法(Kruskal算法)
无向树及生成树PPT文档59页

•
30、风俗可以造就法律,也可以废除 法律。 ——塞·约翰逊
无向树及生成树
66、节制使快乐增加并使享受加强。 ——德 谟克利 特 67、今天应做的事没有做,明天再早也 是耽误 了。——裴斯 泰洛齐 68、决定一个人的一生,以及整个命运 的,只 是一瞬 之间。 ——歌 德 69、懒人无法享受休息之乐。——拉布 克 70、浪费时间是一桩为了生 存,我 们不得 不为自 己编织 一个笼 子,然 后把自 己关在 里面。 ——博 莱索
•
27、法律如果不讲道理,即使延续时 间再长 ,也还 是没有 制约力 的。— —爱·科 克
•
28、好法律是由坏风俗创造出来的。 ——马 克罗维 乌斯
•
29、在一切能够接受法律支配的人类 的状态 中,哪 里没有 法律, 那里就 没有自 由。— —洛克
实习三求无向连通图的生成树

实习三--求无向连通图的生成树实习三求无向连通图的生成树1.需求分析问题描述:若要在n个城市之间建设通信网络,只需要架设n-1条路线即可。
如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题。
基本要求:(1)利用克鲁斯卡尔算法求网的最小生成树,其中,以课本8.7节中的等价类表示构造生成树过程中的连通分量。
(2)利用普里姆算法求网的最小生成树。
(3)以文本文件形式输出生成树中各条边以及他们的权值。
2.设计(1)设计思想:创建邻接矩阵存储结构。
本程序主要分为两个模块:创建邻接矩阵模块,最小生成树模块。
创建邻接矩阵模块:以邻接矩阵的存储形式创建无向网。
最小生成树模块:生成最小生成树,输出其各条边及权值。
(2)概要设计:int型LocateVex函数判断权值在矩阵的位置;声明CraeteGraph函数创建邻接矩阵;声明kruskal函数用于生成最小生成树;声明main函数为程序调用步骤。
(3)设计详细:a.将程序分为两个模块:B.主函数流程图:c.最小生成树流程图(4)调试分析:--变量没定义就使用解决:定义完变量在使用。
--子函数嵌套定义;解决:子函数单独定义,可调用。
--使用数组是越界;解决:注意数组的值,注意不能越界。
(5)用户手册:a.主页面:b.输入顶点数及边数的信息:c.输入顶点信息:d.输入顶点及权值:(6)测试结果:输出最小生成树及权值:(7)源程序:#include<stdio.h>#include<stdlib.h>#include<string.h>#define MAX 100#define MAX_VERTEXNUM 20typedef char Vertex[MAX];//顶点字符串typedef int Adjmatrix[MAX_VERTEXNUM][MAX_VERTEXNUM];//邻接矩阵typedef struct//定义图{Vertex vexs[MAX_VERTEXNUM];Adjmatrix arcs;int vexnum,arcnum;}MGraph;int LocateVex(MGraph* G,Vertex u)//判断权值在矩阵的位置{int i;for(i=0;i<G->vexnum;++i){if(strcmp(G->vexs[i],u)==0)return i;}return -1;}void CreateGraph(MGraph *G)//创建邻接矩阵{int i,j,k,w;Vertex va,vb;printf("请输入顶点数和边数:(用空格隔开)\n");scanf("%d%d",&G->vexnum,&G->arcnum);printf("请输入%d个顶点的信息:(用空格隔开)\n",G->vexnum);for(i=0;i<G->vexnum;++i)scanf("%s",G->vexs[i]);for(i=0;i<G->vexnum;++i)for(j=0;j<G->vexnum;++j)G->arcs[i][j]=MAX;printf("请输入%d条边的两个顶点及权值:(用空格隔开)\n",G->vexnum);for(k=0;k<G->arcnum;++k){scanf("%s%s%d*c",va,vb,&w);i=LocateVex(G,va);j=LocateVex(G,vb);G->arcs[i][j]=G->arcs[j][i]=w;}}void kruskal(MGraph G)//最小生成树{int set[MAX_VERTEXNUM],i,j;int k=0,a=0,b=0,min=G.arcs[a][b];for(i=0;i<G.vexnum;++i)set[i]=i;printf("最小生成树的各条边及权值为:\n");while(k<G.vexnum-1){for(i=0;i<G.vexnum;++i)for(j=0;j<G.vexnum;++j)if(G.arcs[i][j]<min){min=G.arcs[i][j];a=i;b=j;}if(set[a]!=set[b]){printf("%s-%s-%d\n",G.vexs[a],G.vexs[b],G.arcs[a][b]);k++;for(i=0;G.vexnum;i++)if(set[i]==set[b])set[i]=set[a];min=G.arcs[a][b]=G.arcs[b][a]=MAX;}}}void main(){printf("欢迎建设通信网\n");MGraph G;CreateGraph(&G);kruskal(G);}。
无向树和生成树

就不连通了. ❖ 其中n为G中顶点数,m为边数.
5
定理2
❖ 设T=<V,E>是n阶非平凡的树,则T 中至少有2片树叶.
6
证明 因为T是非平凡树,所以T中每个顶点的度 数都大于等于1,设有k片树叶,则有(n-k)个顶点 度数大于等于2,由握手定理可知
15
例1 图G中,实线边所构成的子图是 G的一棵生成树T,求T对应的基本 回路和基本回路系统,基本割集和 基本割集系统.
16
解: G中顶点数n=6,边数m=9,基本回 路个数为m-n+1=4,即T有4条弦f,g,h,i. 对应的基本回路: Cf=facd; Cg=gba; Ch=hdcb; Ci=ied. 基本回路系统为{Cf,Cg,Ch,Ci}
19
Kruskal算法
设n阶无向连通带权图G=<V,E,W> 中有m条边e1,e2···,em,它们带 的权分别为a1,a2,…am,不妨设 a1≤a2≤…≤am.
20
(1)取e1在T中(e1非环,若e2为环,则弃e1); (2)若e2不与e1构成回路,取e2在T中,否则
弃e2,再查e3,继续这一过程,直到形成 生成树T为止.用以上算法生成的T是 最小生成树.
在图2中,实边所示的子图是图G的 一棵生成树T,d,e,f为T的树枝,a,b,c 为T的弦.在T上加弦a,产生G的一 个初级回路aed.在T上加弦b,产生 G的一个初级回路bdf.在T上加弦c, 产生G的一个初级回路cef.这3个 回路中每一个回路都只含一条弦, 其余的边都是树枝,这样的回路称 为基本回路.
17
T有5个树枝a,b,c,d,e,因而有5个基本割集: Sa={a,g,f}; Sb={b,g,h}; Sc={c,f,h}; Sd={d,i,h}; Se={e,f,i};
下面是求无向连同图最小生成树的一种算法概要

6.19下面是求无向连同图最小生成树的一种算法将图中所有边按权从大到小排序后为(e1,e2….emi=1;while (所剩边数 >顶点数{从图中删去 ei如果图不连通,则恢复 eiI++}证明这个算法是正确的。
证明:定理 1:如果一条边 e 被删去了并且没有被恢复, 那么被删去之前 e 一定在某一个环里, 并且在这个环中 e 的权最大。
证明:设 e 被删之前的图为 G 。
如果 e 被删去,并且没有被恢复,说明 e 被删除后图 G-{e}还是连通的。
设 e 连接的两个顶点为 A,B 。
那么 G-{e}中存在 A 到 B 的通路 p 。
于是在 G 中, p+{e}构成一个环。
显然,图 G 中,边的集合 p+{e}中任何一条边被删除都不会破坏 G 的连通性。
因此,按照已知条件,被删除的边 e 一定是 p+{e}中权值最大的一条边。
定理 2:设 C 为任意一个圈, e’ 是圈中权最大的边,那么 G-{e’}中的 MST 也是 G 中的MST 。
证明:设 T 为 G 的任意一棵 MST 。
如果e’ ∈ T ,那么我们来证明可以构造出一个MST 为T’ 使 w(T=w(T’ ,并且e’ 不属于T’ 。
因为 T 是 MST ,那么 T-{e’}分成两个连通分支 G1,G2设集合 S={ e | e∈ G 且 e 的两端分别连接 G1中的某个顶点和 G2中的某个顶点 }(1e’ 为 S 中权最小的元素。
反证法:拿一个比e’ 小的元素替换e’ ,得到一个更小的生成树,矛盾。
(2圈 C 中,除了e’, 至少还有一条边e’’ ∈ S设e’ 连接的两个顶点为 A,B 。
从 C 中去掉e’ 后, A,B 之间还有一条路径 p, 不妨设 A ∈ G1,B ∈ G2。
所以, C 中至少有一条边连接 G1,G2。
(3W(e’’<=W(e’ W表示权因为e’ 是圈中权最大的边于是由 (1(2,得到W(e’’>=W(e’ 。
一个不含回路的连通无向图称为一个树(Tree)

25
1. 前序走訪(Preorder traversal)
先走訪樹根r,再走訪r的左子樹,再走訪r的右子樹
原則:上 左 右(右1右2…)
後代(Descendant) :如h是a的後代
2
e
f
g
內部節點(Internal node)
有兒子的節點,如a,b,c,g
3
h
外部節點(External node)或稱樹葉(Leaf) 沒有兒子的節點,如d,e,f,h
位階(Level) -- 與根的距離,如a的level為0,g的level為2
7
89
11
01
56
13
6.2.3 生成樹;展開樹(Spanning Tree)
一棵樹T是一個連通圖G的生成樹,則T涵蓋G的
所有節點(T spans all vertices of G)。
◦ 生成樹不唯一
G
T
求一個無加權圖(unweighted)的生成樹,有寬度 優先(Breadth-First)與深度優先(Depth-First)兩種 演算法。
高度(Height) -- 與根的最大距離,例如此樹的高度為3 5
m元樹(m-ary Tree)的相關名詞
m元樹:每個節點最多有m個子節點
◦ 二元樹(Binary Tree):m=2 每個節點最多有2個子節點(左右兒子)
a
b
c
◦ 三元樹(Triad-tree) : m=3; 四元樹(Quadtree) m=4 d
无向图的生成树就是从图的边集中选择一些边

无向图的生成树就是从图的边集中选择一些边,使得这些边构成一个连通无环图,也就是树。
如果给每一条边加一个权,所有生成树中权和最小的生成树称为最小生成树。
【Prim算法思想】任意时刻的中间结果都是一棵树,每次花费最小的代价,用一条边把不在树中的结点加进来。
【最小生成树算法实例】现有一张城市地图,图中的顶点为城市,无向边代表两个城市间的连通关系,边上的权代表公路造价。
在分析了这张图后发现,任一对城市都是连通的。
现在要求用公路把所有城市联系起来,如何设计可使得工程的总造价最少?【输入】第一行两个数v(v<=200),e,分别代表城市数和边数以下e行,每行为两个顶点和它们之间的边权w(w<1000)。
【输出】 v-1行,每行为两个城市的序号,表明这两个城市间建一条公路,再加该公路的造价。
【输入样例】6 101 2 101 5 191 6 212 3 52 4 62 6 113 4 64 5 184 6 145 6 33【输出样例】1 2 102 3 52 4 62 6 114 5 18 原图最小生成树program prim_example;Constvmax=200varw:array[1..vmax,1..vmax]of integer;i,j,k,v,e:integer;procedure prim(v0:integer); {v0是开始结点}varflag:array[1..vmax] of boolean;min,prevk,nextk:integer;beginfillchar(flag,sizeof(flag),false);flag[v0]:=true; {先选出v0}for i:=1 to v-1 do {一共寻找v-1条边}beginmin:=maxint;for k:=1 to v doif flag[k] then {找已在集合中的顶点}for j:=1 to v do {求满足条件的边的最小值}if (not(flag[j])) and (w[k,j]<min) and (w[k,j]<>0) then beginmin:=w[k,j]; {记下最小值}nextk:=j;prevk:=k;end;if min<>maxintthen beginflag[nextk]:=true; {最小值对应顶点进入集合}writeln(prevk,' ',nextk,‘ ',min);end;end;{for}end;{prim}beginassign(input,'prim.in');reset(input);assign(output,'prim.out');rewrite(output);fillchar(w,sizeof(w),0);readln(v,e);for k:=1 to e dobeginread(i,j);readln(w[i,j]);w[j,i]:=w[i,j];end;prim(1);close(input);close(output);end.。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实习三求无向连通图的生成树
1•需求分析
问题描述:
若要在n个城市之间建设通信网络,只需要架设n-1条路线即可。
如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题。
基本要求:
(1) 利用克鲁斯卡尔算法求网的最小生成树,其中,以课本8.7节中的等
价类表示构造生成树过程中的连通分量。
(2) 利用普里姆算法求网的最小生成树。
(3) 以文本文件形式输出生成树中各条边以及他们的权值。
2.设计
(1) 设计思想:创建邻接矩阵存储结构。
本程序主要分为两个模块:创建邻接矩阵模块,最小生成树模块。
创建邻接矩阵模块:以邻接矩阵的存储形式创建无向网。
最小生成树模块:生成最小生成树,输出其各条边及权值。
(2) 概要设计:int型LocateVex函数判断权值在矩阵的位置;声明CraeteGraph 函数创建邻接矩阵;声明kruskal函数用于生成最小生成树;声明main函数为程序调用步骤。
(3) 设计详细:a.将程序分为两个模块:
B. 主函数流程图:
C. 最小生成树流程图
(4) 调试分析:--变量没定义就使用
--子函数嵌套定义;
--使用数组是越界;
(5) 用户手册:a.主页面:
解决:定义完变量在使用。
解决:子函数单独定义,可调用。
解决:注意数组的值,注意不能越界
b.输入顶点数及边数的信息:
d.输入顶点及权值
c.输入顶点信息
(6)测试结果:输出最小生成树及
权值 #i nclude<stdio.h>
#i nclude<stdlib.h>
#i nclude<stri ng.h>
#defi ne MAX 100
#defi ne MAX_VERTEXNUM 20
typedef char Vertex[MAX];〃 顶点字符串
typedef int Adjmatrix[MAX_VERTEXNUM][MAX_VERTEXNUM];〃 邻接矩阵 typedef struct//定义图 〔用空格隔
卷迎建设通 请输入顶蕉 譎入m 个顶点的信息* :青紹3条边的两个顶点及权値;〔用空格隔开) 欢迎建
i 珮入 请输入彳个顶点的信息; 論条迪的两个顶点及权值;(用空格隔开)
嚴费矗数颓边数’(用空槨研) 歸
个顶点的信息:(压空格隔开)
最小生成树的各条边及权值
为
1-2-1
飯黑边数:(用空格隔
开)
(用空格隔开)
長和边数:(用空格隔开) (用空格隔开)
嬲边数
Vertex vexs[MAX_VERTEXNUM];
Adjmatrix arcs;
int vex nu m,arc num;
}MGraph;
int LocateVex(MGraph* G,Vertex u)〃判断权值在矩阵的位置
{
int i;
for(i=0;i<G->vex nu m;++i)
{
if(strcmp(G->vexs[i],u)==0)
return i;
}
return -1;
}
void CreateGraph(MGraph *G)〃创建邻接矩阵
{
int i,j,k,w;
Vertex va,vb;
printf("请输入顶点数和边数:(用空格隔开)\n");
sca nf("%d%d",&G->vex num,&G->arc num);
printf("请输入%d个顶点的信息:(用空格隔开)\n",G->vexnum);
for(i=0;i<G->vex nu m;++i)
scan f("%s",G->vexs[i]);
for(i=0;i<G->vex nu m;++i)
for(j=0;j<G->vex nu m;++j)
G->arcs[i][j]=MAX;
printf("请输入%d条边的两个顶点及权值:(用空格隔开)\n",G->vexnum);
for(k=0;k<G->arc nu m;++k)
{
scan f("%s%s%d*c",va,vb,&w);
i=LocateVex(Gva);
j=LocateVex(Gvb);
G->arcs[i][j]=G->arcs[j][i]=w;
}
}
void kruskal(MGraph G)〃最小生成树
{
int set[MAX_VERTEXNUM],i,j;
int k=0,a=0,b=0 ,min=G.arcs[a][b];
for(i=0;i<G .vex nu m;++i)
set[i]=i;
printf("最小生成树的各条边及权值为:\n");
while(k<G.vex num-1)
{
for(i=0;i<G .vex nu m;++i)
for(j=0;j<G .vex nu m;++j)
if(G.arcs[i][j]<mi n)
{
mi n=G.arcs[i][j];
a=i;
b=j;
}
if(set[a]!=set[b])
{
prin tf("%s-%s-%d\n",G.vexs[a],Gvexs[b],G.arcs[a][b]); k++;
for(i=0;G .vex nu m;i++)
if(set[i]==set[b]) set[i]=set[a];
min=G.arcs[a][b]=G.arcs[b][a]=MAX;
}
}
}
void mai n()
{
printf("欢迎建设通信网\n");
MGraph G;
CreateGraph(&G);
kruskal(G);。