栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

最小生成树-1:

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

最小生成树-1:

1.AcWing 1140. 最短网络 - AcWing(连通图求最小生成树)

连通图中求最小生成树建议使用 prime

算法解析:prime 有点类似dijkstra,每次选一个离集合最近的点去加入集合,然后拿这个点去更新剩下连通块中点到这个点的距离,因为这个点在集合中,这个距离也是代表到集合中距离,更新n次后n个点加入到集合中,我们每次拿到的 距离(距离集合最近的点到集合的距离)之和就是最小生成树的大小

算法实现如下:

int prime() {
	memset(dist,0x3f,sizeof dist);
	dist[1] = 0;
    int res = 0;
	for (int i = 1; i <= n; ++i) {
		int t = -1;
		for (int j = 1; j <= n; ++j)
			if (!st[j] && (t == -1 || dist[j] < dist[t]))
				t = j;
		st[t] = true;
		res += dist[t];
		for (int j = 1; j <= n; ++j)
			if(!st[j])dist[j] = min(dist[j],g[t][j]);
	}
	return res;
}

2.1141. 局域网 - AcWing题库(在非连通图中求多个连通块中的最小生成树)

多个连通块中求多个最小生成树建议使用Kruskal

算法 解析:

 Kruskal算法:
1.先将所有边权从小到大排序
2.依次去枚举每条边 a,b,w,如果a和b不连通,
那么就将当前边加入到最小生成树中去

算法核心: 首先题目保证存在生成树(所有点是连通的)
当我们从小到大拿到一条边对应的两点发现他们是不连通的
我们就可以将他们直接连通的边更新为这条边--把他们连通
这条边也就是最小生成树的边

代码实现:

int res = 0;
	for (int i = 0; i < m; ++i) {
		int a = find(e[i].a), b = find(e[i].b);
		if (a != b){
        p[a] = b;
		res += e[i].w;
       }
	}

当然,头铁多个连通块求最小生成树也是可以用prime的 (借用本题第二个大佬   Fighting_Peter ,的题解)

思路解析:在原有的prime算法前加一个for,遍历1-n所有点作为起点的连通块
if st[k]==true ,表示第k个点已经在之前的最小生成树当中了,则continue掉
else 就是一个新的连通块 ,允许他进去更新他这个连通块的内容

int prime() {

	for (int k = 1; k <= n; ++k) { 
		//遍历所有点为起点找连通块,看看他是否已经在一个连通块中
		if (st[k])continue;
		memset(dist,0x3f,sizeof dist);
		for (int i = 0; i < n; ++i) {
			int  t = -1;
			for (int j = 1; j <= n; ++j)
				if (!st[j] && (t == -1 || dist[j] < dist[t]))t = j;
			st[t] = true;
			for (int j = 1; j <= n; ++j)
				if (!st[j])dist[j] = min(dist[j],g[t][j]);
		}
		for (int i = 1; i <= n; ++i)
			if (dist[i] < 0x3f3f3f3f)res += dist[i];
	}
	
	return res;
}

这里的res也就是最小生成树的大小

3.AcWing 1142. 繁忙的都市 - AcWing  -- 非常简单的一道题目,也就是Kruskal的另一个应用

求最小生成树中最大的一条边

4.AcWing 1143. 联络员(算法提高课) - AcWing --这题依然很简单-- 就是Kruskal的选择性插入

5.AcWing 1144. 连接格点 - AcWing

本题思路也比较清晰,但是要注意一些细节处理

题意:给你几条已知边--必选,让你找找至少还需要插入多少权重的边才能形成一颗最小生成树

思路: 和4一样先必选几条边,然后再剩余的边中找到最合适的边插入最小生成树

本体难点:

1.二维化一维,下标从1开始,可以用如下代码实现

for (i = 1, t = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j, ++t)
			g[i][j] = t;

2.由于Kruskal算法不会选择已经加入最短生成树的边,so我们寻找剩余边的时候全部初始化也没问题,因为,那些必选的边最后都会被筛掉,so我们的求所有边代码如下,竖边-1,横边-2

void get_edges() {//排序:先放纵向边--1 ,再放横向边--2
	int dx[4] = { -1,0,1,0 }, dy[4] = { 0,1,0,-1 }, dw[4] = { 1,2,1,2 };
	for (int z = 0; z < 2; ++z)
		for (int i = 1; i <= n; ++i)
			for (int j = 1; j <= m; ++j)
				for (int u = 0; u < 4; ++u)
					if (u % 2 == z) {//先放竖边,在放横边
						int x = i + dx[u], y = j + dy[u], w = dw[u];
						if (x && x <= n && y && y <= m) {
							int a = g[i][j], b = g[x][y];
							if (a < b)e[k++] = { a,b,w };
						}
					}
}

//当然本题也可以不化为一维自己 写一个二维find即可--详情请看本题链接中第二个大佬ZTEG 的题解

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1041279.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号