016-kruskal算法-贪心-《算法设计技巧与分析》M.H.A学习笔记

最小生成树:

在一给定的连通无向图G = (V, E)中,(u, v)
代表连接顶点u与顶点v的边,而
w(u, v)代表此边的权重,若存在T为G的子集且为无循环图,使得w(T)
最小,则此T为G的最小生成树

基本思路:

kruskal算法总共选择n- 1条边,所使用的贪婪准则是:从剩下的边中选择一条不会产生环路的具有最小耗费的边加入已选择的边的集合中。注意到所选取的边若产生环路则不可能形成一棵生成树。kruskal算法分e
步,其中e
是网络中边的数目。按耗费递增的顺序来考虑这e
条边,每次考虑一条边。当考虑某条边时,若将其加入到已选边的集合中会出现环路,则将其抛弃,否则,将它选入。

概括如下:

1. 对G的边按权重非降序排列。

2. 一次取权重最小的边,如果把它放入T不会形成回路的话,则把它放入T中,否则将它丢弃。

判断是否形成回路用并查集。

伪代码:

算法分析:

主要耗费在边的排序,时间复杂度为O(mlogm)。

C++代码:

struct edge {
	int u, v, c;
	bool operator < (const edge &b) const {
		return c < b.c;
	}
}e[mxe];
int n, m;

int fa[mnx];

int find(int x) {
	if(fa[x] != x) fa[x] = find(fa[x]);
	return fa[x];
}

// kruskal 复杂度O(|E|log|E|), |E|:边数
int kruskal() {
	sort(e + 1, e + m + 1);  // 边排序
	for(int i = 1; i <= n; ++i) fa[i] = i; //并查集初始化
	int ret = 0;
	for(int i = 1; i <= m; ++i) {
		int u = e[i].u, v = e[i].v, c = e[i].c;
		u = find(u), v = find(v);
		if(u != v) { //不在同一个集合里面,则把这一条边加入成为最小生成树的一部分
			ret += c;
			fa[u] = v;
		}
	}
	return ret;
}
时间: 2024-10-15 09:42:30

016-kruskal算法-贪心-《算法设计技巧与分析》M.H.A学习笔记的相关文章

五大算法—贪心算法

贪心算法 一.基本概念: 所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解. 贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择.必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关. 所以对所采用的贪心策略一定要仔细分析其是否满足无后效性. 二.贪心算法的基本思路: 1.建立数学模型来描述问题. 2.把求解

高级算法——贪心算法(找零问题)

function makeChange(origAmt, coins) {//贪心算法——找零问题 var remainAmt ; if (origAmt % .25 < origAmt) { coins[3] = parseInt(origAmt / .25); remainAmt = origAmt % .25; origAmt = remainAmt; } if (origAmt % .1 < origAmt) { coins[2] = parseInt(origAmt / .1); r

高级算法——贪心算法(背包问题)

贪心算法不能用来解决离散物品问题的原因是我们无法将“ 半台电视” 放入背包. 规则是按照物品价值高低顺序放入背包. function ksack(values, weights, capacity) { var load = 0; var i = 0; var v = 0; while (load < capacity && i < weights.length) { if (weights[i] <= (capacity - load)) { v += values[i

算法-贪心算法

贪心算法大学的时候就已经学过也弄过,可能周末确实没想到写什么,就顺手学了当年学习的知识,贪心算法(也称为贪婪算法),贪心算法总是作出在当前看来最好的选择.贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择.当然,希望贪心算法得到的最终结果也是整体最优的.虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解. 贪心要素 概念就是这样,如果需要详情可继续搜索获取更多信息,这个时候出现了一个问题,什么使用贪心算法?只需要满足两点即可,首先就是所求解的问题最优

[C++]单源最短路径:迪杰斯特拉(Dijkstra)算法(贪心算法)

1 Dijkstra算法 1.1 算法基本信息 解决问题/提出背景 单源最短路径(在带权有向图中,求从某顶点到其余各顶点的最短路径) 算法思想 贪心算法 按路径长度递增的次序,依次产生最短路径的算法 [适用范围]Dijkstra算法仅适用于[权重为正]的图模型中 时间复杂度 O(n^3) 补充说明 亦可应用于[多源最短路径](推荐:Floyd算法(动态规划,O(n^3))) Dijkstra 时间复杂度:O(n^3) 1.2 算法描述 1.2.1 求解过程(具体思路) 1.2.2 示例 1.2

017-Prim算法-贪心-《算法设计技巧与分析》M.H.A学习笔记

基本思路: 定义结点集合U, V (U表示已经选择加入MST的结点集合,V表示未选) 1. 任选一个结点加入U 2. 选择一条边权最小的边,他的两个结点分别属于U, V,并把属于V的那个结点加入U 3. 重复执行2直到V空 伪代码: C++代码: int g[mnx][mnx]; int n, m; int d[mnx]; // 朴素 prim, 复杂度O(|V|^2) |V|:点数, |E|:边数 int prim() { memset(d, 0x3f, sizeof d); //初始化 in

018-Huffman树-贪心-《算法设计技巧与分析》M.H.A学习笔记

Huffman树是完全二叉树,权重较大的节点距离根较近. Huffman编码是一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字. 基本思路: 建立Huffman树的过程: 假设有n个权值,则构造出的哈夫曼树有n个叶子结点. n个权值分别设为 w1.w2.-.wn,则哈夫曼树的构造规则为: (1) 将w1.w2.-,wn看成是有n 棵树的森林(每棵树仅有一个结点): (2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左.右子树,且新树的根结点权值为其左.右子树

014-背包问题-动态规划-《算法设计技巧与分析》M.H.A学习笔记

01背包: 01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2--Wn,与之相对应的价值为P1,P2--Pn.求能获得的最大总价值. 基本思路: V[i,j]表示从前i件物品中取出的,能装入体积为j的背包的物品的最大总价值. 初始化条件: V[i,0]和V[0,j]都为0,我们从其意义上就可以理解. 状态转移方程: V[i,j]=max{ V[i-1,j],V[i-1,j-Wi]+Pi } ,前后分别为第i件物品不取和取得情况. 总的就是下面的递推式: 算法分析: 表

013--Floyd算法-动态规划-《算法设计技巧与分析》M.H.A学习笔记

多源最短路:有向图,求从每个顶点到其他所有顶点的最短距离. 基本思路: 假设有向图的所有点编号为1到n,l[i,j]表示从i到j的边的长度,如果不存在边,则置为正无穷. 定义d(k,i,j)表示从点i到点j,并且不经过编号大于k的点的最短距离. 初始化条件: K=0时,d(0,i,j)=l[i,j]. 状态转移方程: d(k,i,j)=min{ d(k-1,i,j),d(k-1,i,k)+d(k-1,k,j) }   1<=k<=n 于是我们有如下的递归式: 算法分析: 显然,Floyd算法的