《算法导论》笔记(12) 基本的图算法,最小生成树

  首先是图的表示。G=(V, E),两种标准表示方法。一是邻接链表,一是邻接矩阵。邻接链表有|V|条链表,链表Adj[u]包含所有与结点u有边关联的结点v。邻接矩阵是|V|*|V|的二维矩阵,aij可用来表示结点i与j之间有无边或边的权重。
  广度优先搜素。从源结点出发向外扩展,访问当前结点的全部相连结点并一一入队列,然后将队列中最前结点出列以相同方法访问其子结点,直到所有结点都被访问。访问过程中作两种标记来控制路线,已访问全部子结点的结点标为visited,已访问自身但未访问完其全部子结点的结点标为visiting。s到v的最短距离为v.d,v.d=u.d+1。树边,前驱子图,广度优先树。
BFS(G, s){
  u=s; mark u as visited; u.d=0; queue.push(u);
  while(u){
    for each v in G.Adj[u]{
      if(v not visited && v not visiting) {v.d= u.d + 1; v.p=u; queue.push(v); mark v as visiting; }
    }
    mark u as visited; 
    u=queue.pop();  
  }
}


  深度优先搜索。探索最近发现的结点的边,若无未访问结点,则回溯其前驱结点继续搜索。直到所有结点都访问完全。访问过程中作两种标记来控制路线,已访问全部子结点的结点标为visited,已访问自身但未访问完其全部子结点的结点标为visiting。time来标记结点第一次访问的时间u.d与最后完成全部子结点访问的时间u.f。括号化定理,白色路径定理。树边,后向边,前向边,横向边。深度优先森林。
DFS(G){
  for each u in G{
    if(u not visited && u has no prev_node) visit(u);
  }
}
visit(u){
  time++;    //注意,time作为全局变量,如果多线程同时搜索不同分支的子树,则有同步的问题
  mark u as visiting; u.d=time;
  for each v in G.Adj[u]{
    if(v not visited && v not visiting) {v.p=u; visit(v); }
  }
  time++;
  mark u as visited; u.f=time; 
}


  拓扑排序。有向无环图的所有结点排成线性序列,任意边的起点排在终点之前。方法是在深度优先搜索时,每当结点完成visited则加入一个链表。
  强连通分量。集合内任意两个点,路径(u, v)与(v, u)同时存在,则称为一个强连通分量。寻找强连通分量的算法是运行两次深度优先搜索,第二次是转置图G(V, E' )即所有边方向逆转后的深度优先搜索,并且按照第一次搜索后各结点f值最大值开始搜索。两次搜索完成后形成的深度优先森林是各最大连通分量。证明算法的正确性:假设有结点u与连通分量C,若u.f>C.f,只有两种可能:1,图(V, E)中有路径u->C,此时若在转置图(V, E' )中有路径从u->C则证明u、C在同一连通分量中,u、C可以合并;2,图(V, E)中u、C互相隔离,则转置图G(V, E' )中,u、C也不相连,u不会加入C所在的连通分量。
  最小生成树。已有最小生成树的子集,然后用贪心法选择一条边加入子集。最终所有点加入后,得到最小生成树。 Kruskal算法,选择加入子集的原则是每次一条最短的边加入森林,直到所有点构成一棵最小生成树。Prim算法,每次在子集之外与子集连接的边中选择一条最短的边加入。
MST_Kruskal(G){
  E[]= sorted G.E;
  for each edge(u,v) in E[] {
    if(v not in u.Set){
      add edge(u,v) to A; 
      union(u.Set, v.Set) in one Set;
    } 
  }
}
MST_Prim(G){
  add all vertex in Q;
  edge(u,v) = minimum(G.E); u.key=edge; 
  while(Q not empty){
    u=Q.extract_min; mark u as MST;
    for each v in G.Adj[v]{
      if(v not MST && v.key>w(u,v) ) {v.key=w(u,v); v.p=u; update v in Q;} 
    }
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值