算法描述

lazy普利姆算法的步骤

1.从源点s出发,遍历它的邻接表s.Adj,将所有邻接的边(crossing edges)加入优先队列Q;

2.从Q出队最轻边,将此边加入MST.

3.考察此边的两个端点,对两个端点重复第1步.

示例

从顶点0开始,遍历它的邻接表:边0-7、0-2、0-4、0-6会被加入优先队列Q.

顶点0的邻接表搜索完毕后,边0-7是最轻边,所以它会出队,并加入MST.

如下图:



边0-7出队后,开始考察边的两个端点:

顶点0已经访问过了,跳过;

顶点7还未探索,开始探索顶点7.对7的邻接表进行访问和第一步类似.

我们找到最轻边7-1并加入MST

如下图:

对每条边重复,当所有边都考察完毕,我们就得到了最小生成树,如下图:

时间复杂度

扫描所有边会耗时O(E ).

由于所有的边都会入队,优先队列调整的操作耗时O(logE ).

那lazy方式最差就是O(ElogE ).

其中E 是图的边数.

算法实现

算法的第一步,将源点s所有的邻接的边加入Q,如下:

    /**
* 找出从源点出发的所有的crossing edges,并用一个优先队列维护他们
*
* 原理:
* 将对未访问的邻接点进行遍历当作一次切断(graph-cut),则源点和邻接点间的边就是crossing edge
* 根据贪心策略求MST的要求,要加入的边必须是最轻边(权重最小的边),
* 故而将crossing edges加入优先队列,这样便可用O(logN)的时间找出最小权重边
*
* @param src 源点
*/
private void search(int src) {
visited[src] = true;
for(Edge e : g.vertices()[src].Adj) {
WeightedEdge we = (WeightedEdge)e;
if(!visited[we.to])
crossingEdges.offer(we);
}
}

算法的第二步和第三步如下:

    /**
* lazy普利姆算法中,从一个源点出发
* 1:通过对源点的所有邻接点进行遍历的方式找出所有crossing edges
* 2:将crossing edges中最轻的(拥有最小的权重)边加入MST
* 3:将最轻边的另一个顶点作为源点,重复1-2步.
*
*
* @param src 源点
*/
private void mst(int src) {
search(src);
while (!crossingEdges.isEmpty()) {
WeightedEdge we = crossingEdges.poll();
//懒惰方式处理不再候选的边
if(visited[we.src] && visited[we.to])
continue;
//加入最小生成树
mst.offer(we);
//累积mst的权重
mstWeight += we.weight;
//向src的邻接点方向搜索
if(!visited[we.src])
search(we.src);
//向to的邻接点方向搜索
if(!visited[we.to])
search(we.to);
}
}

其中,维护所有crossing edge的,是一个优先队列:

    /**
* 优先队列,用于维护crossing edges
* 高效返回最轻边
*/
protected PriorityQueue<WeightedEdge> crossingEdges;

带权边的定义很简单,像下面这样:

import java.util.Comparator;

/**
* Created by 浩然 on 4/19/15.
* 带权边
*/
public class WeightedEdge extends Edge implements Comparable<WeightedEdge> {
/**
* 边的权重
*/
public Double weight; /**
* 边的源点
*/
public int src; /**
* 构造一条带权边
*@param src 源点
* @param other 目标点
* @param weight 权重
*/
public WeightedEdge(int src,int other, Double weight) {
super(other);
this.src = src;
this.weight = weight;
} /**
* 比较两条边的大小,这里作升序
* @param to 被比较边
* @return 如果权重比被比较的边小则返回-1,如果大于则返回1,相等则返回0
*/
@Override
public int compareTo(WeightedEdge to) {
if(this.weight < to.weight)
return -1;
else if(this.weight > to.weight)
return 1;
return 0;
}
} public class Edge {
public int to;
public Edge(int key) {
this.to = key;
}
}

而顶点的定义更简单,如下:

public class Vertex {
/**
* 邻接表
*/
public LinkedList<Edge> Adj;
}

完整代码

public class LazyPrim extends Algorithm {

    /**
* 优先队列,用于维护crossing edges
* 高效返回最轻边
*/
protected PriorityQueue<WeightedEdge> crossingEdges; public LazyPrim(WeightedUndirectedGraph g) {
super(g);
} /**
* lazy普利姆算法求MST或MSF(Minimum Spanning Forest最小生成森林)
*
* 算法复杂度:最差O(ElogE)
*/
public void performMST() {
resetMemo();
//对图中的所有顶点进行遍历,找出MST或MSF
for(int i = 0; i < g.vertexCount();i++){
if(!visited[i]) {
mst(i);
}
}
} /**
* lazy普利姆算法中,从一个源点出发
* 1:通过对源点的所有邻接点进行遍历的方式找出所有crossing edges
* 2:将crossing edges中最轻的(拥有最小的权重)边加入MST
* 3:将最轻边的另一个顶点作为源点,重复1-2步.
*
*
* @param src 源点
*/
private void mst(int src) {
search(src);
while (!crossingEdges.isEmpty()) {
WeightedEdge we = crossingEdges.poll();
//懒惰方式处理不再候选的边
if(visited[we.src] && visited[we.to])
continue;
//加入最小生成树
mst.offer(we);
//累积mst的权重
mstWeight += we.weight;
//向src的邻接点方向搜索
if(!visited[we.src])
search(we.src);
//向to的邻接点方向搜索
if(!visited[we.to])
search(we.to);
}
} /**
* 找出从源点出发的所有的crossing edges,并用一个优先队列维护他们
*
* 原理:
* 将对未访问的邻接点进行遍历当作一次切断(graph-cut),则源点和邻接点间的边就是crossing edge
* 根据贪心策略求MST的要求,要加入的边必须是最轻边(权重最小的边),
* 故而将crossing edges加入优先队列,这样便可用O(logN)的时间找出最小权重边
*
* @param src 源点
*/
private void search(int src) {
visited[src] = true;
for(Edge e : g.vertices()[src].Adj) {
WeightedEdge we = (WeightedEdge)e;
if(!visited[we.to])
crossingEdges.offer(we);
}
} @Override
protected void resetMemo() {
super.resetMemo();
//重置优先队列
crossingEdges = new PriorityQueue<>();
}
}

最小生成树-普利姆算法lazy实现的更多相关文章

  1. 最小生成树-普利姆算法eager实现

    算法描述 在普利姆算法的lazy实现中,参考:普利姆算法的lazy实现 我们现在来考虑这样一个问题: 我们将所有的边都加入了优先队列,但事实上,我们真的需要所有的边吗? 我们再回到普利姆算法的lazy ...

  2. 最小生成树-普利姆(Prim)算法

    最小生成树-普利姆(Prim)算法 最小生成树 概念:将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树.最小生成树属于一种树形结构(树形结构是一种特殊的图),或者 ...

  3. 图论---最小生成树----普利姆(Prim)算法

    普利姆(Prim)算法 1. 最小生成树(又名:最小权重生成树) 概念:将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树.最小生成树属于一种树形结构(树形结构是一 ...

  4. POJ-2421-Constructing Roads(最小生成树 普利姆)

    Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 26694   Accepted: 11720 Description The ...

  5. 普利姆算法(prim)

    普利姆算法(prim)求最小生成树(MST)过程详解 (原网址) 1 2 3 4 5 6 7 分步阅读 生活中最小生成树的应用十分广泛,比如:要连通n个城市需要n-1条边线路,那么怎么样建设才能使工程 ...

  6. 图->连通性->最小生成树(普里姆算法)

    文字描述 用连通网来表示n个城市及n个城市间可能设置的通信线路,其中网的顶点表示城市,边表示两城市之间的线路,赋于边的权值表示相应的代价.对于n个定点的连通网可以建立许多不同的生成树,每一棵生成树都可 ...

  7. 最小生成树---普里姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)

    普里姆算法(Prim算法) #include<bits/stdc++.h> using namespace std; #define MAXVEX 100 #define INF 6553 ...

  8. 算法与数据结构(五) 普利姆与克鲁斯卡尔的最小生成树(Swift版)

    上篇博客我们聊了图的物理存储结构邻接矩阵和邻接链表,然后在此基础上给出了图的深度优先搜索和广度优先搜索.本篇博客就在上一篇博客的基础上进行延伸,也是关于图的.今天博客中主要介绍两种算法,都是关于最小生 ...

  9. HDU 1879 继续畅通工程 (Prim(普里姆算法)+Kruskal(克鲁斯卡尔))

    继续畅通工程 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

随机推荐

  1. java基础31 List集合下的Vector集合

    单例集合体系: ---------| collection  单例集合的根接口--------------| List  如果实现了list接口的集合类,具备的特点:有序,可重复       注:集合 ...

  2. MFC的定时函数 SetTimer和结束killTimer

    什么时候我们需要用到SetTimer函数呢?当你需要每个一段时间执行一件事的的时候就需要使用SetTimer函数了. 使用定时器的方法比较简单,通常告诉WINDOWS一个时间间隔,然后WINDOWS以 ...

  3. Centos之关机和重启命令

    shutdown命令 shutdown [选项] 时间 -c:取消前一个关机命令 -h:关机 -r:重启 [root@localhost ~]# date 2017年 06月 21日 星期三 15:4 ...

  4. MySQL约束笔记

    MySQL 查看约束,添加约束,删除约束 添加列,修改列,删除列 · 查看表的字段信息:desc 表名; · 查看表的所有信息:show create table 表名; 添加主键约束:alter t ...

  5. CVE-2012-4792Microsoft Internet Explorer 释放后使用漏洞

    Microsoft Internet Explorer是微软Windows操作系统中默认捆绑的WEB浏览器. Microsoft Internet Explorer 6至8版本中存在释放后使用漏洞.通 ...

  6. C#和PHP 长整型时间互转

    //2018/5/14 16:03:05转换:1526284985 public static double ConvertToDouble(DateTime date) { , , )); var ...

  7. 【51nod】1559 车和矩形

    题解 离线读入,我们发现一个矩形能被保护,矩形内部所有列上必定有一辆车,或者所有行上必定有一辆车 分两次进行处理 第一次按照横坐标把车加进去,然后查询最大横坐标在这个位置的矩形,纵坐标区间里的车出现位 ...

  8. loadrunner 的Administration Page里面设置

    loadrunner 的Administration Page里面设置   1.Set LOGIN form's action tag to an error page.在登录的时候,传递一个动态变量 ...

  9. nginx卸载与安装

    1.卸载 在前面曾经安装过一次,这一次卸载再重新安装. 直接删除文件夹 2.更新软件源 3.依赖包安装 4.下载源码包并解压 5.增加用户组 6.安装 三个步骤 ./configure make ma ...

  10. HDU - 1754 A - I Hate It 线段树

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...