生成树:
生成树是一个图的极小连通分量:
(1)包含图中所有顶点;
(2)只含最少的边,如果增加一条边则会构成回路,减少一条边则会不连通(因为树是一种特殊的图,树一定是连通的,而且树中不会有回路)。
最小生成树(Minimum Spanning Tree, MST):
(1)带权连通无向图;
(2)图的所有生成树中各边权值之和最小的一颗生成树。
特点:
(1)一个图得最小生成树是不唯一的,但最小生成树的各边权值之和是唯一的。
(2)最小生成树的边数是顶点数减一(就是树的特点)。
需要的约束:
(1)只能用图里面有的边;
(2)只能正好用掉|V|-1条边;
(3)不能出现回路。
构造最小生成树算法(贪心策略):
什么是贪:每一步都要最好的;
什么是好:对于最小生成树问题中指的就是权重最小的边。
Prim算法(选择顶点):类似于Dijkstra算法
(1)VT = {v0},ET = {};(VT指对应最小生成树中的顶点,ET指最小生成树中的边,其中VT刚开始随便放入一个顶点,ET刚开始为空,也就是现在对应的最小生成树中有一个结点,但没有边,之后要做的事情就是让这颗树一点一点长大);
(2)在所有的属于集合VT中的顶点u,和所有的属于集合V - VT中的顶点v构成的边(u, v)中,找一颗权重最小的边(贪),收入边集,同时把顶点v收入VT中;
(3)直到VT=V时结束,此时树中刚好有|V| - 1条边。
(4)时间复杂度:T= O(|V|^2),不依赖于|E|,所以在稠密图的时候比较适合。
Kruskal算法(选择边):更直截了当的贪心
(1)VT = V, ET = {};(刚开始就把原所给图的所有顶点收录到VT中,但边集为空,此时就相当于每个顶点是一颗独立的树,此时VT相当于一个森林);
(2)从E - ET中选一条权值最小的边,如果这条边加入当前正在生成的树中不构成回路的话,就把它收录进ET中;
(3)重复上述操作直到ET中有|V| - 1条边,而对于顶点每收进一条边就把对应两个顶点对应的树合并起来,直至把森林合并成一棵树;
(4)时间复杂度:O(|E|log|E|)(采用最小堆存储边,采用并查集描述最小生成树的过程),所以这种算法在稀疏图的时候比较适合。
两个算法的实现MOOC上和王道上都是伪码,所以把具体实现放在之后第二遍的时候再做。