《啊哈!算法》 第八章 更多精彩的算法

 第一节  镖局运镖-图的最小生成树

所谓最小生成树,就是在一个具有N个顶点的带权连通图G中,如果存在某个子图G‘,其包含了图G中的所有顶点和一部分边,且不形成回路,并且子图G‘的各边权值之和最小,则称G‘为图G的最小生成树。

最小生成树的三个性质

  • 最小生成树不能有回路
  • 最小生成树可能是一个,也可能有多个
  • 最小生产树的边的个数等于顶点的个数减一

Kruskal 算法(选边法)

其核心思想是:首先按照边的权值进行从小到大排序,每次从剩余的边中选择权值较小且边的两个顶点不在同一个集合的边(就是不会产生回路的边),加入到生产树中,直到加入了n-1条边为止。其实现是 贪心+并查集

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct edge{
    int u;
    int v;
    int w;
    edge(int uu =0, int vv= 0, int ww = 0):u(uu),v(vv),w(ww){}

    bool operator<(const edge& a) const{
        return w < a.w;
    }
};

vector<int> f;

//建立并查集
void make_set(int n){
    for(int i = 0 ; i <= n; ++ i) f.push_back(i);
}

//查询并查集
int find_set(int x){
    if(f[x] == x) return x;
    else{
        f[x] = find_set(f[x]);
        return f[x];
    }
}

//合并子集
bool union_set(int x, int y){
    int t1 = find_set(x), t2 = find_set(y);
    if(t1!=t2){
        f[t2] = t1;
        return true;
    }
    return false;
}

int main(){
    int n,m;
    cin >> n >> m;
    vector<edge> e(m+1);
    for(int i = 1 ; i <= m; ++ i){
        cin >> e[i].u >> e[i].v >> e[i].w;
    }
    sort(e.begin(),e.end());
    int sum = 0, cnt = 0;
    make_set(n);
    for(int i = 1; i <= m ; ++ i){
        if(union_set(e[i].u,e[i].v)){
            cnt++;
            sum+=e[i].w;
        }
        if(cnt == n-1) break;
    }
    cout<<sum<<endl;
}

Kruskal算法

 n代表顶点数,m代表边数,对边的快速排序时间复杂度是O(MlogM),在m条边中找出n-1条边是O(MlogN),所以Krusal算法时间复杂度为O(MlogM+MlogN),通常M大于N,因此最终时间复杂度为O(MlogM)。

第二节 再谈最小生成树

Prim算法(选点法)

其核心思想是:首先选择任意一个顶点加入生成树中,接下来找出一条边添加到生成树中,这需要枚举每一树顶点(已被选入生产树的顶点)到每一个非树顶点所有的边,然后找出最短的边加入到生成树中。

#include <iostream>
#include <vector>
#include <algorithm>
#define INF 100000
using namespace std;

int main(){
    int n,m;
    cin >> n >> m;
    vector<vector<int> > e(n,vector<int>(n,INF));
    for(int i = 0 ; i <  n; ++ i) e[i][i] = 0;
    for(int i = 0 ; i < m; ++ i){
        int u,v,w;
        cin>> u >> v >> w;
        --u;--v;
        e[u][v] = w; e[v][u] = w;
    }
    vector<int> dist(e[0].begin(),e[0].end());
    vector<bool> visit(n,false);
    visit[0 ] = true;
    int cnt = 1,sum = 0;
    while(cnt < n){
        int minw = INF,index = 0;
        for(int i = 0; i  < n ; ++ i){
            if(!visit[i] && dist[i] <  minw){
                minw = dist[i];
                index = i;
            }
        }
        visit[index] = true;
        cnt++;
        sum +=minw;

        for(int k = 0; k < n; ++ k){
            if(!visit[k] && dist[k]> e[index][k]){
                dist[k] = e[index][k];
            }
        }
    }
    cout<<sum<<endl;
}

Prim算法

上述Prim算法如果使用邻接矩阵来保存图的话,时间复杂度是O(N^2),观察代码很容易发现,时间主要浪费在每次都要遍历所有点找一个最小距离的顶点,对于这个操作,我们很容易想到用堆来优化,使得每次可以在log级别的时间找到距离最小的点,然后使用邻接表存储图,整个算法的时间复杂度会降到O(mlogn)

Kruskal算法更适用于稀疏图,没有使用堆优化的Prim算法适用于稠密图,使用了堆优化的Prim算法更适用于稀疏图

《啊哈!算法》 第八章 更多精彩的算法

时间: 2024-07-28 18:55:44

《啊哈!算法》 第八章 更多精彩的算法的相关文章

C# 抽象类理解与使用 【果断收藏,更多精彩...】

一.一码当先---代码清单 抽象基类People 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ///  ///    抽象基类   ///  public abstract class People  {      public string Name;      public string Gender;      public People(string outName, string outGender)      {          Nam

关注CSDN社区微信,更多精彩等你来

CSDN社区微信公众号"程序人生"(微信ID)来了,每天我们会将CSDN社区中大量的优质内容浓缩成1~3篇文章,推送到您的手机中,让您无论何时何地都能感受到知识的精彩.技术的力量. 扫描二维码关注: 关注后的精彩: CSDN博客平台中最优质的博文(也许就有您的文章) CSDN论坛平台中最火热的讨论(精彩不容错过) CSDN下载平台中最实用的开发资源(让开发事半功倍) CSDN社区最新的有奖活动(奖品拿到手软) 最大机会免费获得CSDN的各种福利(技术大会门票.<程序员>杂志

c++第十八章-(容器和算法)

容器和算法 容器: 容器的概念:能容纳两个或更多个值的数据结构,通常我们称为容器(container). 这么说,数组是唯一直接支持的容器,但数组并不适合用来解决所有的问题. 上一节利用模板就实现了一种新的容器(栈Stack). 老一辈程序员为我们提供了一种容器库,Standard Template Library.STL库. 算法: 数组大小固定的,后来引入了一种新的数据类型,vector向量, 声明:std::vector<type> vectorName; #include <ve

链接挖掘算法之PageRank算法和HITS算法

参考资料:http://blog.csdn.net/hguisu/article/details/7996185 更多数据挖掘算法:https://github.com/linyiqun/DataMiningAlgorithm 链接分析 在链接分析中有2个经典的算法,1个是PageRank算法,还有1个是HITS算法,说白了,都是做链接分析的.具体是怎么做呢,继续往下看. PageRank算法 要说到PageRank算法的作用,得先从搜索引擎开始讲起,PageRank算法的由来正式与此相关. 搜

韩顺平_PHP程序员玩转算法公开课(第一季)01_算法重要性_五子棋算法_汉诺塔_回溯算法_学习笔记_源代码图解_PPT文档整理

文西马龙:http://blog.csdn.net/wenximalong/ 课程说明:算法是程序的灵魂,为什么有些网站能够在高并发,和海量吞吐情况下依然坚如磐石,大家可能会说: 网站使用了服务器集群技术.数据库读写分离和缓存技术(比如memcahced和redis等),那如果我再深入的问一句,这些优化技术又是怎样被那些天才的技术高手设计出来的呢? 我在上大学的时候就在想,究竟是什么让不同的人写出的代码从功能看是一样的,但从运行效率上却有天壤之别, 就拿以前在软件公司工作的实际经历来说吧, 我是

算法9-2:最大流Ford-Fulkerson算法

本节介绍最大流算法的基本思想. 首先将整个网络的最大容量都设为0. 然后增加第一条边的流量,达到最大流量. 增加第二条边的流量,达到最大流量. 增加第三条边的流量,达到最大流量.这里需要注意的是,图中有一条反向的边(称之为后向弧).后向弧的作用就是说,可以将后向弧中的流量移动到别的线路中,这样可以增加更多的流量. 同样的,在第四条边中也有反向弧,通过反向弧增加更多的流量. 算法结束的依据是判断所有的路径都达到下列任意条件: 容量已经满了 反向弧是空的 这就是Ford-Fulkerson算法的基本

浅析负载均衡的6种算法,Ngnix的5种算法。

浅析负载均衡的6种算法,Ngnix的5种算法.?浮生偷闲百家号03-21 10:06关注内容导读其实际效果越来越接近于平均分配调用量到后端的每一台服务器,也就是轮询的结果.源地址哈希的思想是根据获取客户端的IP地址,通过哈希函数计算得到的一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是客服端要访问服务器的序号.采用源地址哈希法进行负载均衡,同一IP地址的客户端,当后端服务器列表不变时,它每次都会映射到同一台后端服务器进行访问.不同的后端服务器可能机器的配置和当前系统的负载并不相同

看的见的算法 7个经典应用诠释算法精髓

第1章 欢迎来到看得见的算法欢迎来到看得见的算法.这个课程将以独一无二的方式,向你展示算法究竟有什么用,在实际项目中能做什么,并向你一一展示通过学习这个课程,你将能够制作出多么酷炫的程序:)1-1 欢迎来到看得见的算法1-2 学习这个课程将完成什么项目?1-3 关于本课程的编程环境1-4 更多学习本课程的注意事项 第2章 要想看得见,先要搞定GUI编程在这一章,你将从0开始接触Java Swing编程,进入GUI的编程世界.通过这一章的学习,你将了解Java Swing最基本的用法.在这一章的最

EM算法(1):K-means 算法

目录 EM算法(1):K-means 算法 EM算法(2):GMM训练算法 EM算法(3):EM算法详解 EM算法(1) : K-means算法 1. 简介 K-means算法是一类无监督的聚类算法,目的是将没有标签的数据分成若干个类,每一个类都是由相似的数据组成.这个类的个数一般是认为给定的. 2. 原理 假设给定一个数据集$\mathbf{X} = \{\mathbf{x}_1, \mathbf{x}_2,...,\mathbf{x}_N \}$, 和类的个数K.我们的每个类都用一个中心点$