第十三章 最小生成树
智慧树知到《数据结构》章节测试答案
第1章单元测试1、算法的时间复杂度取决于___。
答案:A和B2、数据在计算机内存中的表示是指()答案:数据的存储结构3、算法指的是()答案:求解特定问题的指令有限序列4、在数据结构中,与所使用的计算机无关的数据结构是()答案:逻辑7、某线性表采用顺序存储结构,每个元素占4个存储单元,首地址为100,则第12个元素的存储地址为( )。
答案:1448、算法能正确地实现预定功能的特性称为算法的()。
答案:正确性第2章单元测试1、链表不具备的特点是()。
答案:可随机访问任意一个结点3、线性表的顺序存储表示优于链式存储表示。
答案:错4、顺序存储结构的缺点是不便于修改,插入和删除需要移动很多结点。
答案:对5、在设头、尾指针的单链表中,与长度n有关的操作是( )。
答案:删除最后一个结点6、设指针q指向单链表中结点A,指针p指向单链表中结点A的后继结点B,指针s指向被插入的结点X,则在结点A和结点B间插入结点X的操作序列为( )。
答案:q->next=s; s->next=p;7、对于只在表的首、尾两端进行插入操作的线性表,宜采用的存储结构为( )。
答案:用尾指针表示的循环单链表8、在一个单链表中,若p所指节点不是最后节点,在p之后插入s所指节点,则执行( )。
答案:s->link=p->link;p->link=s;9、在双向链表存储结构中,删除p所指的结点时须修改指针____。
答案:p->next->prior=p->prior; p->prior->next=p->next;10、若事先不知道线性表的长度,则处理线性表时较好的存储结构是( )。
答案:单链表11、向一个有127个元素的顺序表中插入一个新元素并保存,原来顺序不变,平均要移动( )个元素。
答案:63.512、某线性表采用顺序存储结构,每个元素占4个存储单元,首地址为100,则第12个元素的存储地址为( )。
最小生成树是否唯一
最小生成树是否唯
昊宇亮 ,孔凡龙 ( 中师范大学,武 汉 4 0 7 华 30 9) 摘
i h h peo h i m u s n n e sn tu q . ee i h t rt ep o s d mi m u s n n te ,n eo ytr e ft es a ftem ni m pa nig t ei o niueD tr new ehe h r po e ni m pa nig ea dt nl h e r m r h wa st v i n lssa d v la in. y ogiet ra ay i n e au to he K e w o dsM i i u pa ni e ; q ePrm l o i y r : nm m s n ngt eUniu ; i a g rt ; u ka lort r hm Kr s lag i hm; m als a nig te S l pn n e r
一
要 :最小生成树是图论的经典问题 ,求最小生成树以及求最小生成树的权值和得到了足够关注,而很少人去研究最小生
成树是否唯一 。对于给定的 图而言 ,因为最小生成树 的权值和是确 定的 ,所以最 小生成树 不唯 一当且仅 当最 小生成树 的形状 不唯 本文提 出判断最 小生成树是 否唯 一的三种方法并且 对它们给予分析和评价。
。
关键 词 :最小 生成树 ;唯 一 ;pi 法 ;ku a r m算 rs l ;次 小 生成树 k 算法 中图分类号 :T 31 文献标识码:A P 0. 6 文章编号:10 - 5 9 (0 1 0 — 02 0 07 99 2 1 ) 6 0 7- 2
图论第一章课后习题解答
bi 个 (i = 1,2,…,s),则有 列。 定理 7
bi = n。故非整数组(b ,b ,…, b )是 n 的一个划分,称为 G 的频序
1 2 s
s
i 1
一个 n 阶图 G 和它的补图 G 有相同的频序列。
§1.2 子图与图的运算
且 H 中边的重数不超过 G 中对应边的 定义 1 如果 V H V G ,E H E G , 重数,则称 H 是 G 的子图,记为 H G 。有时又称 G 是 H 的母图。 当 H G ,但 H G 时,则记为 H G ,且称 H 为 G 的真子图。G 的生成子图是 指满足 V(H) = V(G)的子图 H。 假设 V 是 V 的一个非空子集。以 V 为顶点集,以两端点均在 V 中的边的全体为边集 所组成的子图,称为 G 的由 V 导出的子图,记为 G[ V ];简称为 G 的导出子图,导出子图 G[V\ V ]记为 G V ; 它是 G 中删除 V 中的顶点以及与这些顶点相关联的边所得到的子图。 若 V = {v}, 则把 G-{v}简记为 G–v。 假设 E 是 E 的非空子集。以 E 为边集,以 E 中边的端点全体为顶点集所组成的子图 称为 G 的由 E 导出的子图,记为 G E ;简称为 G 的边导出子图,边集为 E \ E 的 G 的 导出子图简记为 G E 。若 E e ,则用 G–e 来代替 G-{e}。 定理 8 简单图 G 中所有不同的生成子图(包括 G 和空图)的个数是 2m 个。 定义 2 设 G1,G2 是 G 的子图。若 G1 和 G2 无公共顶点,则称它们是不相交的;若 G1 和 G2 无公共边,则称它们是边不重的。G1 和 G2 的并图 G1∪G2 是指 G 的一个子图,其顶点 集为 V(G1)∪V(G2),其边集为 E(G1)∪E(G2);如果 G1 和 G2 是不相交的,有时就记其并图为 G1+G2。类似地可定义 G1 和 G2 的交图 G1∩G2,但此时 G1 和 G2 至少要有一个公共顶点。
最小生成树(Kruskal算法)
三、方案解决:
在本题中我们将采用 Kruskal 算法来构造最小生成树。 从题目所给赋权图中我们可以得到该图的邻接矩阵为:
⎡ 0 20 0 0 0 23 1 ⎤ ⎢20 0 15 0 0 0 4 ⎥ ⎢ ⎥ ⎢ 0 15 0 3 0 0 9 ⎥ ⎢ ⎥ G = ⎢ 0 0 3 0 17 0 16 ⎥ ⎢ 0 0 0 17 0 28 25⎥ ⎢ ⎥ ⎢ 23 0 0 0 28 0 36⎥ ⎢ 1 4 9 16 25 36 0 ⎥ ⎣ ⎦
-3-
6.选择造价第五小的序号为 5 的边,即 S 23 ,由于加入后边 S 23 , S 27 , S37 将构成回路,因此 舍弃该边 如图所示:
7.选择造价第六小的序号为 6 的边,即 S 47 ,由于加入后边 S34 , S37 , S 47 将构成回路,因此 舍弃该边 如图所示:
8.选择造价第七小的序号为 7 的边,即 S 45 ,加入 T 中,此时 T={{6},{ S17 , S34 , S 27 , S37 ,
S 45 , S16 }},Cost=34+23=57
如图所示:
11.算法结束 此时,所有顶点已包含在树中,整棵最小生成树已经构造完成。即应该在城市{(1,7) , (2,7) , (3,7) , (3,4) , (4,5) , (1,6)}之间建造通信道路,可使得城市间相互通信又造价费 用最小,此时可以得到其最小的费用为 57 万元
-7-
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); Mincost+=edges[i].weight; } } printf("使各城市间能够通信的最小费用为:Mincost=%d\n",Mincost); } int Find(int *parent, int f) { while ( parent[f] > 0) { f = parent[f]; } return f; }
离散数学最小生成树例题
离散数学最小生成树例题
离散数学最小生成树例题是:
给定一个带权无向图G,其中顶点集V={1,2,3,4,5},边集E={(1,2),(1,3),(1,4),(2,5),(3,5)},权值集合W={1,2,3,4,5}。
用Kruskal算法求最小生成树。
首先对边集E和权值集合W按照边的权值从小到大进行排序;然后初始化一个空的并查集和一个空的森林;将并查集的根节点设置为第一个顶点,森林中添加这个顶点;对于每一条边,如果它的两个顶点不在同一个集合中,将这条边添加到森林中,并将这两个顶点合并到同一个集合中;最后森林中的边就是最小生成树。
数据结构,最小生成树克鲁斯卡尔算法的实现
摘要设计了一个用C/C++编写程序实现克鲁斯卡尔最小生成树算法,该程序操作简单,界面清晰,易于为用户所接受。
关键词:克鲁斯卡尔,邻接矩阵,最小生成树,vc++。
目录1 课题描述 (1)2 问题分析和任务定义 (2)3 逻辑设计 (3)4 详细设计 (4)5 程序编码 (11)6 程序调试与测试 (17)7 结果分析 (19)8 总结 (20)参考文献 (21)1课题描述用C/C++编写程序实现克鲁斯卡尔最小生成树算法。
假设要在n 个城市之间建立通讯联络网,则连通n个城市只需要n-1条线路。
这是我们设计一个最小生成树的程序用来算出最节省经费的前提下建立这个通信站。
2问题分析和任务定义假设连通网N=(V,{E}),则令最小生成树的初始状态为只有n 个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。
在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。
依次类推,直到T中所有顶点都在同一连通分量上为止。
设计思想:采用邻接矩阵来存储图,然后采用克鲁斯卡尔算法求出最小生成树。
1).定义结构体。
2).采用邻接矩阵做存储结构创建图(函数模块一)。
3).采用克鲁斯卡尔算法求出该图的最小生成树(函数模块二)。
4).在主函数里面分别调用以上各个函数,最终实现设计目的。
4.1.程序结构·函数CreateMGraph用来实现图的创建,以及图的相关信息的存储。
图的存储采用邻接矩阵存储结构。
·函数minitree_KRUSKAL用来求图的最小生成树。
图的最小生成树有普利姆算法和克鲁斯卡尔算法可以实现,本段代码使用的是克鲁斯卡尔算法,这也是本题所要求使用的。
·各个函数间的联系先调用函数CreateMGraph实现图的创建,然后调用函数minitree_KRUSKAL求出该图的最小生成树4.2.设计说明·在开始的时候添加一些限制条件方便函数的功能实现例如:#define MaxVertexNum 100 //最大顶点个数#define QueueSize 30#define M 30·模块一:图的创建·结构体定义为:typedef struct{VertexType vexs[MaxVertexNum]; //顶点表Link edges[MaxVertexNum][MaxVertexNum]; //图中当前的相连接的两个顶点int n,e; //图中当前的顶点数和边数}MGraph;·函数定义为:MGraph CreateMGraph(){MGraph G;int i,j,k,ch3;char ch1,ch2;printf("请输入该图的顶点数和边数:\n");scanf("%d,%d",&(G.n),&(G.e));printf("请输入该图的顶点信息:\n");for(i=1;i<=G.n;i++){getchar();scanf("%c",&(G.vexs[i]));}for(i=1;i<=G.n;i++)for(j=1;j<=G.n;j++)G.edges[i][j].w=0;printf("请输入该图每条边对应的两个顶点的名称:\n");for(k=1;k<=G.e;k++){scanf("%c",&ch1);printf("请输入第%d条边的顶点序号:",k);scanf("%c %c",&ch1,&ch2);printf("请输入第%d条边的权值大小:",k);scanf("%d",&ch3);for(i=1;ch1!=G.vexs[i];i++);for(j=1;ch2!=G.vexs[j];j++);e[p].vexh=i;e[p].vext=j;e[p].weight=G.edges[i][j].w=ch3; //权值e[p].flag=0;p++;}return G;}流程如图4.1所示创建图使用的是函数MGraph CreateMGraph(),该图的存储结构是邻接矩阵,先对图的结构体进行定义,再进行初始化。
数据结构之最小生成树Prim算法
数据结构之最⼩⽣成树Prim算法普⾥姆算法介绍 普⾥姆(Prim)算法,是⽤来求加权连通图的最⼩⽣成树算法 基本思想:对于图G⽽⾔,V是所有顶点的集合;现在,设置两个新的集合U和T,其中U⽤于存放G的最⼩⽣成树中的顶点,T存放G的最⼩⽣成树中的边。
从所有uЄU,vЄ(V-U) (V-U表⽰出去U的所有顶点)的边中选取权值最⼩的边(u, v),将顶点v加⼊集合U中,将边(u, v)加⼊集合T中,如此不断重复,直到U=V为⽌,最⼩⽣成树构造完毕,这时集合T中包含了最⼩⽣成树中的所有边。
代码实现1. 思想逻辑 (1)以⽆向图的某个顶点(A)出发,计算所有点到该点的权重值,若⽆连接取最⼤权重值#define INF (~(0x1<<31)) (2)找到与该顶点最⼩权重值的顶点(B),再以B为顶点计算所有点到改点的权重值,依次更新之前的权重值,注意权重值为0或⼩于当前权重值的不更新,因为1是⼀当找到最⼩权重值的顶点时,将权重值设为了0,2是会出现⽆连接的情况。
(3)将上述过程⼀次循环,并得到最⼩⽣成树。
2. Prim算法// Prim最⼩⽣成树void Prim(int nStart){int i = 0;int nIndex=0; // prim最⼩树的索引,即prims数组的索引char cPrims[MAX]; // prim最⼩树的结果数组int weights[MAX]; // 顶点间边的权值cPrims[nIndex++] = m_mVexs[nStart].data;// 初始化"顶点的权值数组",// 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。
for (i = 0; i < m_nVexNum; i++){weights[i] = GetWeight(nStart, i);}for (i = 0; i < m_nVexNum; i ++){if (nStart == i){continue;}int min = INF;int nMinWeightIndex = 0;for (int k = 0; k < m_nVexNum; k ++){if (weights[k]!= 0 && weights[k] < min){min = weights[k];nMinWeightIndex = k;}}// 找到下⼀个最⼩权重值索引cPrims[nIndex++] = m_mVexs[nMinWeightIndex].data;// 以找到的顶点更新其他点到该点的权重值weights[nMinWeightIndex]=0;int nNewWeight = 0;for (int ii = 0; ii < m_nVexNum; ii++){nNewWeight = GetWeight(nMinWeightIndex, ii);// 该位置需要特别注意if (0 != weights[ii] && weights[ii] > nNewWeight){weights[ii] = nNewWeight;}}for (i = 1; i < nIndex; i ++){int min = INF;int nVexsIndex = GetVIndex(cPrims[i]);for (int kk = 0; kk < i; kk ++){int nNextVexsIndex = GetVIndex(cPrims[kk]);int nWeight = GetWeight(nVexsIndex, nNextVexsIndex);if (nWeight < min){min = nWeight;}}nSum += min;}// 打印最⼩⽣成树cout << "PRIM(" << m_mVexs[nStart].data <<")=" << nSum << ": ";for (i = 0; i < nIndex; i++)cout << cPrims[i] << "";cout << endl;}3. 全部实现#include "stdio.h"#include <iostream>using namespace std;#define MAX 100#define INF (~(0x1<<31)) // 最⼤值(即0X7FFFFFFF)class EData{public:EData(char start, char end, int weight) : nStart(start), nEnd(end), nWeight(weight){} char nStart;char nEnd;int nWeight;};// 边struct ENode{int nVindex; // 该边所指的顶点的位置int nWeight; // 边的权重ENode *pNext; // 指向下⼀个边的指针};struct VNode{char data; // 顶点信息ENode *pFirstEdge; // 指向第⼀条依附该顶点的边};// ⽆向邻接表class listUDG{public:listUDG(){};listUDG(char *vexs, int vlen, EData **pEData, int elen){m_nVexNum = vlen;m_nEdgNum = elen;// 初始化"邻接表"的顶点for (int i = 0; i < vlen; i ++){m_mVexs[i].data = vexs[i];m_mVexs[i].pFirstEdge = NULL;}char c1,c2;int p1,p2;ENode *node1, *node2;// 初始化"邻接表"的边for (int j = 0; j < elen; j ++){// 读取边的起始顶点和结束顶点p1 = GetVIndex(c1);p2 = GetVIndex(c2);node1 = new ENode();node1->nVindex = p2;node1->nWeight = pEData[j]->nWeight;if (m_mVexs[p1].pFirstEdge == NULL){m_mVexs[p1].pFirstEdge = node1;}else{LinkLast(m_mVexs[p1].pFirstEdge, node1);}node2 = new ENode();node2->nVindex = p1;node2->nWeight = pEData[j]->nWeight;if (m_mVexs[p2].pFirstEdge == NULL){m_mVexs[p2].pFirstEdge = node2;}else{LinkLast(m_mVexs[p2].pFirstEdge, node2);}}}~listUDG(){ENode *pENode = NULL;ENode *pTemp = NULL;for (int i = 0; i < m_nVexNum; i ++){pENode = m_mVexs[i].pFirstEdge;if (pENode != NULL){pTemp = pENode;pENode = pENode->pNext;delete pTemp;}delete pENode;}}void PrintUDG(){ENode *pTempNode = NULL;cout << "邻接⽆向表:" << endl;for (int i = 0; i < m_nVexNum; i ++){cout << "顶点:" << GetVIndex(m_mVexs[i].data)<< "-" << m_mVexs[i].data<< "->"; pTempNode = m_mVexs[i].pFirstEdge;while (pTempNode){cout <<pTempNode->nVindex << "->";pTempNode = pTempNode->pNext;}cout << endl;}}// Prim最⼩⽣成树void Prim(int nStart){int i = 0;int nIndex=0; // prim最⼩树的索引,即prims数组的索引char cPrims[MAX]; // prim最⼩树的结果数组int weights[MAX]; // 顶点间边的权值cPrims[nIndex++] = m_mVexs[nStart].data;// 初始化"顶点的权值数组",// 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。
最小生成树
}edge[111边的条数,s用来存放最小生成树的总权值 int root[111];//存储父节点
bool cmp(Edge a,Edge b) {
return a.d<b.d; } int find(int a)//寻找父节点
T1
u
顶 点 集 U
u'
T2 v
顶 点 集 V-U
13
应用举例——最小生成树
Prim算法
34 B 12
A 19
26 E
F
46 25
25 38
C
D
17
U={A}
V-U={B, C, D, E, F}
cost={(A, B)34, (A, C)46, (A, D)∞, (A, E)∞, (A, F)19}
最小生成树
生成树是一个连通图G的一个极小连通子 图。包含G的所有n个顶点,但只有n-1条 边,并且是连通的。
当生成树中所包含的边的权值和最小, 我们称之为最小生成树。
最小生成树性质
最小生成树的边数必然是顶点数减一,|E| = |V| - 1。 最小生成树不可以有循环。 最小生成树不必是唯一的。
16
应用举例——最小生成树
Prim算法
34 B 12
A 19
26 E
F
46 25
25 38
C
D
17
U={A, F, C, D} V-U={B, E} cost={(A, B)34, (F, E)26}
{ if(root[a]==a) return a; return root[a]=find(root[a]);
管理运筹学课后习题
第一章思考题、主要概念及内容1、了解运筹学的分支,运筹学产生的背景、研究的内容和意义。
2、了解运筹学在工商管理中的应用。
3、体会管理运筹学使用相应的计算机软件,注重学以致用的原则。
第二章思考题、主要概念及内容图解法、图解法的灵敏度分析复习题1. 考虑下面的线性规划问题:max z=2x1+3x2;约束条件:x1+2x2≤6,5x1+3x2≤15,x1,x2≥0.(1) 画出其可行域.(2) 当z=6时,画出等值线2x1+3x2=6.(3) 用图解法求出其最优解以及最优目标函数值.2. 用图解法求解下列线性规划问题,并指出哪个问题具有惟一最优解、无穷多最优解、无界解或无可行解.(1) min f=6x1+4x2;约束条件:2x1+x2≥1,3x1+4x2≥3,x1,x2≥0.(2) max z=4x1+8x2;约束条件:2x1+2x2≤10,-x1+x2≥8,x1,x2≥0.(3) max z=3x1-2x2;约束条件:x1+x2≤1,2x1+2x2≥4,x1,x2≥0.(4) max z=3x1+9x2;约束条件:-x1+x2≤4,x2≤6,2x1-5x2≤0,x1,x2≥03. 将下述线性规划问题化成标准形式:(1) max f=3x1+2x2;约束条件:9x1+2x2≤30,3x1+2x2≤13,2x1+2x2≤9,x1,x2≥0.(2) min f=4x1+6x2;约束条件:3x1-x2≥6,x1+2x2≤10,7x1-6x2=4,x1,x2≥0.(3) min f=-x1-2x2;约束条件:3x1+5x2≤70,-2x1-5x2=50,-3x1+2x2≥30,x1≤0,-∞≤x2≤∞.(提示:可以令x′1=-x1,这样可得x′1≥0.同样可以令x′2-x″2=x2,其中x′2,x″2≥0.可见当x′2≥x″2时,x2≥0;当x′2≤x″2时,x2≤0,即-∞≤x2≤∞.这样原线性规划问题可以化为含有决策变量x′1,x′2,x″2的线性规划问题,这里决策变量x′1,x′2,x″2≥0.)4. 考虑下面的线性规划问题:min f=11x1+8x2;约束条件:10x1+2x2≥20,3x1+3x2≥18,4x1+9x2≥36,x1,x2≥0.(1) 用图解法求解.(2) 写出此线性规划问题的标准形式.(3) 求出此线性规划问题的三个剩余变量的值.5. 考虑下面的线性规划问题:max f=2x1+3x2;约束条件:x1+x2≤10,2x1+x2≥4,2x1+x2≤16,x1,x2≥0.(1) 用图解法求解.(2) 假定c2值不变,求出使其最优解不变的c1值的变化范围.(3) 假定c1值不变,求出使其最优解不变的c2值的变化范围.(4) 当c1值从2变为4,c2值不变时,求出新的最优解.(5) 当c1值不变,c2值从3变为1时,求出新的最优解.(6) 当c1值从2变为25,c2值从3变为25时,其最优解是否变化?为什么?6. 某公司正在制造两种产品,产品Ⅰ和产品Ⅱ,每天的产量分别为30个和120个,利润分别为500元/个和400元/个.公司负责制造的副总经理希望了解是否可以通过改变这两种产品的数量而提高公司的利润.公司各个车间的加工能力和制造单位产品所需的加工工时如表2-4(25页)所示.表2-4(1) 假设生产的全部产品都能销售出去,用图解法确定最优产品组合,即确定使得总利润最大的产品Ⅰ和产品Ⅱ的每天的产量.(2) 在(1)所求得的最优产品组合中,在四个车间中哪些车间的能力还有剩余?剩余多少?这在线性规划中称为剩余变量还是松弛变量?(3) 四个车间加工能力的对偶价格各为多少?即四个车间的加工能力分别增加一个加工时数时能给公司带来多少额外的利润?(4) 当产品Ⅰ的利润不变时,产品Ⅱ的利润在什么范围内变化,此最优解不变?当产品Ⅱ的利润不变时,产品Ⅰ的利润在什么范围内变化,此最优解不变?(5) 当产品Ⅰ的利润从500元/个降为450元/个,而产品Ⅱ的利润从400元/个增加为430元/个时,原来的最优产品组合是否还是最优产品组合?如有变化,新的最优产品组合是什么?第三章思考题、主要概念及内容“管理运筹学”软件的操作方法“管理运筹学”软件的输出信息分析复习题1. 见第二章第7题,设x1为产品Ⅰ每天的产量,x2为产品Ⅱ每天的产量,可以建立下面的线性规划模型:max z=500x1+400x2;约束条件:2x1≤300,3x2≤540,2x1+2x2≤440,1.2x1+1.5x2≤300,x1,x2≥0.使用“管理运筹学”软件,得到的计算机解如图3-5)所示根据图3-5回答下面的问题:(1) 最优解即最优产品组合是什么?此时最大目标函数值即最大利润为多少?(2) 哪些车间的加工工时数已使用完?哪些车间的加工工时数还没用完?其松弛变量即没用完的加工工时数为多少?(3) 四个车间的加工工时的对偶价格各为多少?请对此对偶价格的含义予以说明.(4) 如果请你在这四个车间中选择一个车间进行加班生产,你会选择哪个车间?为什么?(5) 目标函数中x1的系数c1,即每单位产品Ⅰ的利润值,在什么范围内变化时,最优产品的组合不变?(6) 目标函数中x2的系数c2,即每单位产品Ⅱ的利润值,从400元提高为490元时,最优产品组合变化了没有?为什么?(7) 请解释约束条件中的常数项的上限与下限.(8) 第1车间的加工工时数从300增加到400时,总利润能增加多少?这时最优产品的组合变化了没有?(9) 第3车间的加工工时数从440增加到480时,从图3-5中我们能否求得总利润增加的数量?为什么?(10) 当每单位产品Ⅰ的利润从500元降至475元,而每单位产品Ⅱ的利润从400元升至450元时,其最优产品组合(即最优解)是否发生变化?请用百分之一百法则进行判断.(11) 当第1车间的加工工时数从300增加到350,而第3车间的加工工时数从440降到380时,用百分之一百法则能否判断原来的对偶价格是否发生变化?如不发生变化,请求出其最大利润.2. 见第二章第8题(2),仍设xA为购买基金A的数量,xB为购买基金B的数量,建立的线性规划模型如下:max z=5xA+4xB;约束条件:50xA+100xB≤1 200 000,100xB≥300 000,xA,xB≥0.使用“管理运筹学”软件,求得计算机解如图3-7所示.根据图3-7,回答下列问题:(1) 在这个最优解中,购买基金A和基金B的数量各为多少?这时获得的最大利润是多少?这时总的投资风险指数为多少?(2) 图3-7中的松弛/剩余变量的含义是什么?(3) 请对图3-7中的两个对偶价格的含义给予解释.(4) 请对图3-7中的目标函数范围中的上、下限的含义给予具体说明,并阐述如何使用这些信息.(5) 请对图3-7中的常数项范围的上、下限的含义给予具体说明,并阐述如何使用这些信息.(6) 当投资总金额从1 200 000元下降到600 000元,而在基金B上至少投资的金额从300 000元增加到600 000元时,其对偶价格是否发生变化?为什么?3. 考虑下面的线性规划问题:min z=16x1+16x2+17x3;约束条件:x1+x3≤30,05x1-x2+6x3≥15,3x1+4x2-x3≥20,x1,x2,x3≥0.其计算机求解结果如图3-9所示.根据图3-9,回答下列问题:(1) 第二个约束方程的对偶价格是一个负数(为-3622),它的含义是什么?(2) x2的相差值为0703,它的含义是什么?(3) 当目标函数中x1的系数从16降为15,而x2的系数从16升为18时,最优解是否发生变化?(4) 当第一个约束条件的常数项从30减少到15,而第二个约束条件的常数项从15增加到80时,你能断定其对偶价格是否发生变化吗?为什么?第四章思考题、主要概念及内容人力资源的分配问题;生产计划的问题;套裁下料问题;配料问题;投资问题。
避圈法求最小生成树例题
避圈法求最小生成树例题避圈法是一种求解最小生成树的算法,它适用于不连通图。
在不连通图中,我们需要在所有顶点之间构建虚拟边,以便将它们连成一个环。
然后我们从环中删除一些边,这样最终剩下的边将形成最小生成树。
以下是一个使用避圈法求解最小生成树的例题:给定一个n个顶点的无向连通图,其中顶点编号为O到n-lo要求将这个图改造成一个没有边相邻的图,使得改造后的图的权值之和最小。
请输出改造后图的权值之和。
输入格式:输入的第一行包含一个整数n(2≤n≤1000),表示图中的顶点数。
接下来的n-1行,每行包含两个整数U和V(0≤u,V≤n-l,u≠v),表示顶点U和顶点V之间有一条边。
输出格式:输出一个整数,表示改造后图的权值之和。
示例:输入:4011 22 330输出:16解题思路:1.初始化虚拟源点s和虚拟汇点to2.对于每个顶点,计算从顶点到虚拟源点的距离dist[u]β3.对于每个顶点,计算从顶点到虚拟汇点的距离dist[v]β4.对于每个顶点,遍历虚拟边,尝试将顶点u和顶点V连接起来。
如果此时构建了环,则不需要将虚拟边加入最小生成树。
5.如果遍历虚拟边后没有构建环,则将顶点u和顶点V连接起来的边加入最小生成树,并更新虚拟边的权值为Oo6.最终最小生成树的权值之和即为改造后图的权值之和o代码实现(PythOn):defminspanningtree(G,s,t,dist):n-Ien(G)parent=[-1]*nmincost=0min_dist=float(,inf,)foruinrange(n):min_cost+=G[u][s]mindist=min(mindist,dist[u])parent[u]=useen=setOdeffind(u):ifparent[u]!=-1:parent[u]=find(parent[u])returnparent[u]defunion(u,v):ifdist[u]+G[u][v]<dist[v]:dist[v]=dist[u]+G[u][v]parent[v]二Udefmain():n=int(input())G=[list(map(int,inputO.split()))for_inrange(n)]s=G[0][0]t=G[n-1][0]dist=[float(,inf,)]*(n+1)dist[s]=0min_spanning_tree(G,s,t,dist)cost=0foru,vinzip(G[:-l],G[l:]):cost+=G[u][v]print(cost)iΓname main()_main_':注意:本例题中,我们假设图是连通的。
智慧树知到《数据结构》章节测试答案
第1章单元测试1、算法的时间复杂度取决于___。
答案:A和B2、数据在计算机内存中的表示是指()答案:数据的存储结构3、算法指的是()答案:求解特定问题的指令有限序列4、在数据结构中,与所使用的计算机无关的数据结构是()答案:逻辑7、某线性表采用顺序存储结构,每个元素占4个存储单元,首地址为100,则第12个元素的存储地址为( )。
答案:1448、算法能正确地实现预定功能的特性称为算法的()。
答案:正确性第2章单元测试1、链表不具备的特点是()。
答案:可随机访问任意一个结点3、线性表的顺序存储表示优于链式存储表示。
答案:错4、顺序存储结构的缺点是不便于修改,插入和删除需要移动很多结点。
答案:对5、在设头、尾指针的单链表中,与长度n有关的操作是( )。
答案:删除最后一个结点6、设指针q指向单链表中结点A,指针p指向单链表中结点A的后继结点B,指针s指向被插入的结点X,则在结点A和结点B间插入结点X的操作序列为( )。
答案:q->next=s; s->next=p;7、对于只在表的首、尾两端进行插入操作的线性表,宜采用的存储结构为( )。
答案:用尾指针表示的循环单链表8、在一个单链表中,若p所指节点不是最后节点,在p之后插入s所指节点,则执行( )。
答案:s->link=p->link;p->link=s;9、在双向链表存储结构中,删除p所指的结点时须修改指针____。
答案:p->next->prior=p->prior; p->prior->next=p->next;10、若事先不知道线性表的长度,则处理线性表时较好的存储结构是( )。
答案:单链表11、向一个有127个元素的顺序表中插入一个新元素并保存,原来顺序不变,平均要移动( )个元素。
答案:63.512、某线性表采用顺序存储结构,每个元素占4个存储单元,首地址为100,则第12个元素的存储地址为( )。
最小生成树
2、普里姆(Prim)算法1)算法的基本思想:普里姆算法的基本思想:普里姆算法是另一种构造最小生成树的算法,它是按逐个将顶点连通的方式来构造最小生成树的。
从连通网络 N = { V, E }中的某一顶点 u0 出发,选择与它关联的具有最小权值的边(u0, v),将其顶点加入到生成树的顶点集合U中。
以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u, v),把该边加入到生成树的边集TE中,把它的顶点加入到集合U中。
如此重复执行,直到网络中的所有顶点都加入到生成树顶点集合U中为止。
假设G=(V,E)是一个具有n个顶点的带权无向连通图,T(U,TE)是G的最小生成树,其中U 是T的顶点集,TE是T的边集,则构造G的最小生成树T的步骤如下:(1)初始状态,TE为空,U={v0},v0∈V;(2)在所有u∈U,v∈V-U的边(u,v) ∈E中找一条代价最小的边(u′,v′)并入TE,同时将v′并入U;重复执行步骤(2)n-1次,直到U=V为止。
在普里姆算法中,为了便于在集合U和(V-U)之间选取权值最小的边,需要设置两个辅助数组closest和lowcost,分别用于存放顶点的序号和边的权值。
对于每一个顶点v∈V-U,closest[v]为U中距离v最近的一个邻接点,即边(v,closest[v]) 是在所有与顶点v相邻、且其另一顶点j∈U的边中具有最小权值的边,其最小权值为lowcost[v],即lowcost[v]=cost[v][closest[v]],采用邻接表作为存储结构:设置一个辅助数组closedge[]:lowcost域存放生成树顶点集合内顶点到生成树外各顶点的各边上的当前最小权值;adjvex域记录生成树顶点集合外各顶点距离集合内哪个顶点最近(即权值最小)。
应用Prim算法构造最小生成树的过程:如下所示为构造生成树的过程中,辅助数组中各分量值的变化情况,初始归U={v1},加入到U集合中的节点,我们将lowcost改成0以示:Prim算法1.概览普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。
最小生成树课程设计
最小生成树课程设计一、课程目标知识目标:1. 学生能够理解最小生成树的概念,掌握其定义和性质;2. 学生能够掌握两种常见的最小生成树算法:普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法;3. 学生能够运用最小生成树解决实际问题,如网络设计、电路设计等。
技能目标:1. 学生能够运用图论知识,分析并解决最小生成树问题;2. 学生能够编写和调试实现最小生成树的算法程序;3. 学生能够通过小组合作,共同探讨并解决最小生成树相关问题。
情感态度价值观目标:1. 学生通过学习最小生成树,培养对图论的兴趣,激发探索数学问题的热情;2. 学生在合作解决问题的过程中,学会沟通、协作,培养团队精神;3. 学生能够认识到数学知识在实际生活中的广泛应用,增强学习的积极性和主动性。
课程性质:本课程为计算机科学、信息技术等相关专业的高年级学生设计,旨在帮助学生掌握最小生成树的基本原理和算法,提高解决实际问题的能力。
学生特点:学生已经具备一定的图论基础,熟悉基本的算法和数据结构,具有一定的编程能力。
教学要求:通过讲解、示例、练习和小组讨论等形式,使学生掌握最小生成树的相关知识,提高编程实践能力和解决问题的能力。
同时,注重培养学生的团队合作精神和数学思维。
二、教学内容1. 最小生成树概念与性质- 定义、性质和判定条件- 最小生成树的应用场景2. 普里姆(Prim)算法- 算法原理与步骤- 代码实现与调试- 算法性能分析3. 克鲁斯卡尔(Kruskal)算法- 算法原理与步骤- 代码实现与调试- 算法性能分析4. 最小生成树算法比较与应用- 普里姆与克鲁斯卡尔算法的优缺点对比- 实际问题中的应用案例分析5. 小组讨论与练习- 分组讨论最小生成树相关算法及应用- 编写和调试最小生成树算法程序- 解决实际问题,如网络设计、电路设计等教学内容安排与进度:第一周:最小生成树概念与性质,普里姆算法原理与实现第二周:普里姆算法性能分析,克鲁斯卡尔算法原理与实现第三周:克鲁斯卡尔算法性能分析,最小生成树算法比较与应用第四周:小组讨论与练习,解决实际问题教材章节:《离散数学及其应用》第6章:图论《数据结构与算法分析》第9章:图论算法《计算机算法设计与分析》第4章:最小生成树与最短路径三、教学方法本课程将采用以下多样化的教学方法,以激发学生的学习兴趣和主动性:1. 讲授法:教师通过生动的语言、形象的比喻和具体的案例,讲解最小生成树的概念、性质和算法原理,使学生系统掌握理论知识。
图的最小生成树_prim算法
4 最小生成树
①初始化候选边数组edges[]; ② U={v0}; ③for (i=1; i<=n-1; i++) { k=最小候选边的未选的一端; U=U+{k}; 以k修改edges[]; } 注:edges的元素可以设置为{v} 思考:权值最小的边一定在最小生成树中么? 分析 : prim算法的时间复杂度?
1
12 15
9
9 5 4
2
17
6 9 10 3 4
(1,2)/12 (1,3)/∞
3
{1,6} {1,6,5}
(1,2)/12 (6,3)/17 (6,4)/20 (6,2)/15 (6,4)/20 (1,2)/12 (6,3)/17 (5,4)/4 (6,2)/15 (1,2)/12 (6,3)/17 (6,2)/15 (4,3)/3
2
6 15 17 3 3 6 9 10 4
7
5 4
4 最小生成树
1 12 2 6 15 17 3 3 9 6 9 10 4 9 5 4 2 6 12 15 17 3
1 9
6 9 12 5 4 4 2 6 15 17 3
1 9
6 9
9
10
9
10
5 4 4
3
1
3
1
1 12 9 15 17 3 3 6 9 10 4 9 5 4 2 6
6
4 最小生成树
问题:修建一个连接各个小区与供应站点之间的管道使得造价成本最 低,即构造一颗最小生成树。但是如何求解? 4.1 prim算法 1. 基本思想 在满足如下条件的过程中选出一条最小的边: 一端已选,另一端未选。 因此,该算法需要给出起点,以作为已选顶点。 2. 实例 1 对右图所示图, 12 9 9 用Prim算法求最小生成树。
基于完全图的求解最小生成树算法
基于完全图的求解最小生成树算法1. 引言最小生成树是图论中的一个重要问题,它涉及到如何在一个无向连通图中找到一棵生成树,使得所有边的权值之和最小。
经典的 Kruskal 算法和 Prim 算法是目前最著名的两种求解最小生成树问题的算法。
而本文将介绍一种基于完全图的求解最小生成树算法。
2. 算法原理基于完全图的求解最小生成树算法,其本质是一个贪心算法。
它的实现过程如下:1)给定一个无向完全图 G。
2)初始化:将 G 中所有边标记为未选中状态,并选取一个顶点作为起点。
3)在剩余的边中选择权值最小的边 e,如果加入 e 后出现了环,则选择下一条边。
否则,将 e 加入生成树,并将 e 标记为已选中状态。
4)重复步骤 3,直到所有顶点都被访问。
3. 实现代码如下:``` pythondef min_spanning_tree(G):"""基于完全图的求解最小生成树算法:param G: 无向完全图,使用邻接矩阵保存,G[i][j] 表示顶点i 与 j 之间的边的权值:return: 最小生成树的邻接矩阵"""INF = float('inf') # 定义正无穷n = len(G) # 顶点数MST = [[INF] * n for i in range(n)] # 最小生成树邻接矩阵visited = [0] * n # 标记顶点是否访问过visited[0] = 1 # 选取第一个顶点for i in range(n-1): # n-1 条边min_distance = INFx, y = -1, -1for j in range(n):if visited[j]:for k in range(n):if not visited[k] and G[j][k] < min_distance:min_distance = G[j][k]x, y = j, kif x != -1 and y != -1:visited[y] = 1 # 标记已经访问的顶点MST[x][y] = G[x][y]MST[y][x] = G[x][y] # 更新最小生成树中的边return MST```4. 时间复杂度由于我们要对完全图的所有边进行排序,因此时间复杂度为O(n^2)。
避圈法求最小生成树例题
避圈法求最小生成树例题避圈法是一种求解最小生成树的算法,它适用于不连通图。
在不连通图中,我们需要在所有顶点之间构建虚拟边,以便将它们连成一个环。
然后我们从环中删除一些边,这样最终剩下的边将形成最小生成树。
以下是一个使用避圈法求解最小生成树的例题:给定一个 n 个顶点的无向连通图,其中顶点编号为 0 到 n-1。
要求将这个图改造成一个没有边相邻的图,使得改造后的图的权值之和最小。
请输出改造后图的权值之和。
输入格式:输入的第一行包含一个整数 n (2 ≤ n ≤ 1000),表示图中的顶点数。
接下来的 n-1 行,每行包含两个整数 u 和 v (0 ≤ u, v ≤ n-1, u ≠ v),表示顶点u 和顶点 v 之间有一条边。
输出格式:输出一个整数,表示改造后图的权值之和。
示例:输入:40 11 22 33 0输出:16解题思路:1. 初始化虚拟源点 s 和虚拟汇点 t。
2. 对于每个顶点,计算从顶点到虚拟源点的距离 dist[u]。
3. 对于每个顶点,计算从顶点到虚拟汇点的距离 dist[v]。
4. 对于每个顶点,遍历虚拟边,尝试将顶点 u 和顶点 v 连接起来。
如果此时构建了环,则不需要将虚拟边加入最小生成树。
5. 如果遍历虚拟边后没有构建环,则将顶点 u 和顶点 v 连接起来的边加入最小生成树,并更新虚拟边的权值为 0。
6. 最终最小生成树的权值之和即为改造后图的权值之和。
代码实现(Python):def min_spanning_tree(G, s, t, dist):n = len(G)parent = [-1] * nmin_cost = 0min_dist = float('inf')for u in range(n):min_cost += G[u][s]min_dist = min(min_dist, dist[u])parent[u] = useen = set()def find(u):if parent[u] != -1:parent[u] = find(parent[u])return parent[u]def union(u, v):if dist[u] + G[u][v] < dist[v]:dist[v] = dist[u] + G[u][v]parent[v] = udef main():n = int(input())G = [list(map(int, input().split())) for _ in range(n)] s = G[0][0]t = G[n - 1][0]dist = [float('inf')] * (n + 1)dist[s] = 0min_spanning_tree(G, s, t, dist)cost = 0for u, v in zip(G[:-1], G[1:]):cost += G[u][v]print(cost)if __name__ == '__main__':main()注意:本例题中,我们假设图是连通的。
最小树_运筹学_[共8页]
156运筹学图6.17 生成树此时41k E V ==−+,这样得到了生成树。
6.2.3 最小树最小树是网络优化中的一个重要概念,在交通网、电力网、通讯网等的设计中均有广泛的应用。
定义6.2.3 设连通图G V E =(,)。
每条边i j e v v =(,)上都有一个非负权数ij w e w =()。
若1T V E =(,)是G 的一个生成树,则称1E 中所有边的权之和为生成树T 的权,记为()ij w T w =∑。
称具有最小权的生成树为G 的最小生成树,简称为最小树。
显然,对于最小树,有如下结论成立。
定理6.2.2 若把连通网络图的所有点分成V 和V 两个集合,则两集合之间连线的最短边一定包含在最小树内。
下面介绍如何寻找或构建一个最小树的几种算法。
算法1 Kruskal 算法1956年Kruskal 给出了求最小树问题的一种算法。
其基本思想是从网络中逐步挑选边构成最小生成树。
每次挑选的边对应的权要尽可能小,但必须保证已选好的边不产生圈。
这种方法称为Kruskal 算法,也称为避圈法。
这种方法与求生成树的避圈法类似。
避圈法步骤如下。
Step1 把图中的所有顶点分成V 和V 两个集合。
从图中任选一点i v ,让i v V ∈,图中其余点均包含在V 中。
Step2 从V 和V 的连线中找出最小边,这条边一定包含在最小树内,不妨设最小边为i j v v (,),将i j v v (,)标记成最小树内的边。
令{}j V V v =∪,{}\j V V v =。
Step3 若V =Φ,则算法终止。
否则转入Step2。
例6.6 一个乡有9个自然村,其间道路及各个道路长度如图6.18所示,各边上的数表示距离,问如何拉线才能使用线最短。
解 用Kruskal 算法。
Step1 令{}1V v =,{}02345678V v v v v v v v v =,,,,,,,。
Step2 {}12101818min 1w w w w ==,,。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
6
1 5 1 3
(2,5) (3,6)
4
2 3
(1,4) (3,4)
4
5 6
2
最小代价生成树
(2,3)
添加
{1,3,4,5,6,2}
算法难点及解决方案
如何从所有边中选择代价最小的边:边放入一个优先级 队列,边的优先级就是它的权值。权值越小,优先级越 高。 用并查集来实现。将一个连通分量表示为并查集中的一 个子集,检查一条边加入后会不会形成回路可以通过对 边的两个端点分别执行Find操作。如果两个Find的结果相 同,则表示两个端点已连通,加入这条边会形成回路, 否则将这条边加入生成树。添加边的操作就是一个 Union 操作,将两个端点所属的子集归并起来,表示其中的所 有顶点都已连通。
第13章 最小生成树
生成树与最小生成树 Kruskal算法 Prim算法 算法的正确性
Kruscal 算法
基本思想:考虑图中权值最小的边。如果 加入这条边不会导致回路,则加入;否则 考虑下一条边,直到包含了所有的顶点 实现:
初始时,设置生成树为(V,Φ),如果V有n 个顶点,则初始的生成树为具有n个连通分量的 树。 按权值的大小逐个考虑所有的边,如果该边的 加入能连接两个连通分量,则加入。当生成树 只有一个连通分量时,算法结束。
kruskal算法的实现
template <class TypeOfVer, class TypeOfEdge> void adjListGraph<TypeOfVer, TypeOfEdge>::kruskal( ) const { int edgesAccepted = 0,u, v; edgeNode *p; edge e; DisjointSet ds( Vers ); //定义一个并查集 priorityQueue<edge> pq; //定义一个关于边的优先级队列
无向图G A E H M C D C B 无向图G的生成树 A E H M D B
最小生成树 (Minimum spanning tree, MST)
定义:加权无向图的所有生成树中边的权值(代价) 之和最小的树。
最小代价生成树
1 6 2 5 6 5 1 3 4 5 5 4 2 3 5 5 1 1 3 4 6 4 2
3
2
6
6
Application: Network design
Applications
MST is fundamental problem with diverse applications.
Dithering. Cluster analysis. Max bottleneck paths. Real-time face verification. LDPC codes for error correction. Image registration with Renyi entropy. Find road networks in satellite and aerial imagery. Reducing data storage in sequencing amino acids in a protein. Model locality of particle interactions in turbulent fluid flows. Autoconfig protocol for Ethernet bridging to avoid cycles in a network. Approximation algorithms for NP-hard problems (e.g., TSP, Steiner tree). Network design (communication, electrical, hydraulic, computer, road). /~eppstein/gina/mst.html
1 6 2 3 5 5 6 1 3 4 5 5 4 2 6
1、初始连通分量: {1},{2},{3},{4},{5},{6}
2、反复执行添加、放弃动作。
边
(1,3) (4,6)
动作
添加 添加 添加 添加 放弃 放弃
连通分量
{1,3},{4},{5},{6},{2} {1,3},{4, 6},{2},{5} {1,3},{4, 6},{2,5} {1,3,4, 6},{2,5} 因构成回路 因构成回路
prim算法运行过程中startNode和 lowCost数组的变化
编号
0 6 1 3 4 5 6 6 1 2 4 5 5 5 3 2
startNode
lowCost
编号
visited
0
1 2 3 4 5
随机值
20 随机值 随机值 0 随机值 2 5 0 25 1 随机值 随机值 2
∞
6 ∞ 5 1 ∞ 5∞ 2 5 ∞ 3 6 4 ∞
第13章 最小生成树
生成树与最小生成树 Kruskal算法 Prim算法 算法的正确性
Prim算法
从顶点的角度出发。初始时,顶点集U为空,然 后逐个加入顶点,直到包含所有顶点。 过程:首先选择一个顶点,加入顶点集。然后重 复下列工作,直到U = V
选择连接U 和V-U 中代价最小的边(u,v) 把(u,v)加入生成树的边集,v加入到U
如何判断加入一条边后会不会形成回路:
定义优先级队列中的元素类型
struct edge { int beg, end; //边的起点、终点和权值 TypeOfEdge w; bool operator<(const edge &rp) const {return w < rp.w;} //重载小于运算符 };
start = 0; //将0作为第一个加入U中结点 for ( i= 1; i < Vers; ++i) { //共找n-1条边, 检查start的边,对于start的每一条
边(start, v),如果v不在生成树中,并且边的权值w小于lowCost[v]时更新
for (p = verList[start].head; p != NULL; p = p->next) if (!flag[p->end] && lowCost[p->end] > p->weight) { lowCost[p->end] = p->weight; //更新距离 startNode[p->end] = start; } flag[start] = true; //将start加入U中 min = noEdge; for (j = 0; j < Vers; ++j) //寻找权值最小的边 if (lowCost[j] < min) {min = lowCost[j]; start = j;} //将j加入U cout << '(' << verList[startNode[start]].ver << ',‘ << verList[start].ver << ")\t"; lowCost[start] = noEdge; //不再考虑这条边 } delete [ ] flag; delete [ ] startNode; delete [ ] lowCost; }
//将所有的边放入优先级队列
for (int i = 0; i< Vers; ++i) { for (p = verList[i].head; p != NULL; p = p->next) if (i < p->end) { //每条边只入队一次 e.beg = i; e.end = p->end; e.w = p->weight; pq.enQueue(e); } }
数据结构 Data Structure
第十三章 最小生成树
第13章 最小生成树
生成树与最小生成树 Kruskal算法 Prim算法 算法的正确性
生成树
生成树是无向连通图的极小连通子图。包含图的 所有 n 个结点,但只含图的 n-1 条边。在生成树 中添加一条边之后,必定会形成回路或环。
flag[i]=ture 表示结点i在U中,否则表示结点i不在U中。 //用两个一维数组lowCost和startNode来记录U中的结点到V-U中结点的 权值最小的边。 TypeOfEdge *lowCost = new TypeOfEdge[Vers]; //表示U中的结 点到结点i的边的最小权值。 int *startNode = new int[Vers]; //表示从U中的哪一个结点出发到结 点i的权值是lowCost[i]。
时间复杂度
生成优先级队列的for循环将所有的边入队。需要 执行|E|次入队,建堆时间为log|E|, 生成优先级队 列所需时间是O(|E|log|E|)。 在最坏的情况下,归并的循环可能需要检查所有 的边。对于每条边,最多需要执行两次Find操作 和一次Union操作。因此,归并循环的最坏情况的 时间复杂度是O(|E|log|V|)。 在一个连通图中,一般边数总比结点数大,所以, Kruskal算法的时间复杂度是O(E|log|E|)。
//开始归并
while( edgesAccepted < Vers - 1 ) //选择边数不满n-1时 { e = pq.deQueue(); //取出权值最小的边 u = ds.Find(e.beg); v = ds.Find(e.end); if( u != v ) //边的起点和终点在不同的连通子图 { edgesAccepted++; ds.Union( u, v ); //加入(u,v)归并两个连通子图 cout << '(' << verList[e.beg].ver << ',' << verList[e.end].ver << ")\t"; } } }