• 学习记录:最小生成树


    最小生成树

    最小生成树是无向图中额一个典型问题。问题模型可以用以下的方式描述:

    给定无向图,要求连接所有的点,并求出此时最小的边长度总和。

    模板题:P3366 【模板】最小生成树

    前置知识:并查集,贪心,存图方法

    prim算法

    简介:

    是对的贪心算法。从任意一点开始,选取距离该点最近的一点加入集合中,再从剩下的点中找出距离集合最近的一点,加入到集合中;重复以上过程,直到所有点都在集合中。(有点像Dijstra)

    但与Dijstra不同的是,prim算法不需要松弛操作。最终记录在dis数组上的不是出发点到目标点的距离,而是集合到目标点的最短距离。顺带一提,prim不需要并查集的知识。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rp1(i, a, b) for (int i = a; i < b; i++)
    #define rp2(i, a, b) for (int i = a; i <= b; i++)
    typedef long long ll;
    typedef unsigned long long ull;
    
    int mod = 9973;
    const int INF = 0x3f3f3f3f;
    const int maxn = 5e3 + 10;
    
    int Map[maxn][maxn];
    int vis[maxn];
    int dis[maxn];
    int n, m, flag = 0;
    
    void Prim()
    {
    	rp2(i, 1, n)
    		dis[i] = Map[1][i]; //dis数组初始化
    	int res = 0;			//最终答案
    	dis[1] = 0;
    	vis[1] = 1;
    	rp1(k, 0, n - 1) //循环n-1次,因为连接n个点最少需要n-1条边
    	{
    		int u = INF;
    		int pos;
    		rp2(i, 1, n)
    		{
    			if (!vis[i] && u > dis[i])
    			{
    				pos = i; //找到最短点,并记录
    				u = dis[i];
    			}
    		}
    		if (u == INF) //不是连通图
    		{
    			cout << "orz" << endl;
    			exit(0);
    		}
    		vis[pos] = 1;
    		res += u;
    		rp2(i, 1, n)
    		{
    			if (!vis[i] && dis[i] > Map[pos][i]) //与Dijstra不同的地方
    				dis[i] = Map[pos][i];
    		}
    	}
    	printf("%d
    ", res);
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	rp2(i, 1, n)
    		rp2(j, 1, n)
    			Map[i][j] = (i == j) ? 0 : INF;
    	for (int i = 1; i <= m; i++)
    	{
    		int x, y, z;
    		scanf("%d%d%d", &x, &y, &z);
    		Map[x][y] = Map[y][x] = min(z, Map[x][y]); //洛谷这个相当坑,路径可能是重的,要取最小值
    	}
    	Prim();
    }
    

    kruskal 算法

    简介:

    对边进行贪心操作。在所有边中寻找最短的边,加入集合中;如果形成闭环,则去除该边;直到最小生成树建立完成。

    要注意的是,在kruskal中判断重边,应用了并查集。每当选定一条边时,判断当前的两个端点是否在一个集合里。如果是,则形成了闭环,这条边不要。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rp1(i, a, b) for (int i = a; i < b; i++)
    #define rp2(i, a, b) for (int i = a; i <= b; i++)
    typedef long long ll;
    typedef unsigned long long ull;
    
    int mod = 9973;
    const int INF = 0x3f3f3f3f;
    const int maxn = 2e5 + 10;
    
    int S[maxn];
    struct Edge
    {
    	int x, y, z;
    } edge[maxn];
    bool cmp(Edge a, Edge b) { return a.z < b.z; }
    int find(int u)
    {
    	while (u != S[u])
    		u = S[u] = S[S[u]];
    	return u;
    }
    int n, m;
    
    int kruskal()
    {
    	int ans = 0;
    	for (int i = 1; i <= n; i++)
    		S[i] = i;
    	sort(edge + 1, edge + 1 + m, cmp);
    	for (int i = 0; i < m; i++)
    	{
    		int b = find(edge[i].x);
    		int c = find(edge[i].y);
    		if (b == c)
    			continue;
    		S[c] = b;
    		ans += edge[i].z;
    	}
    	return ans;
    }
    int main()
    {
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= m; i++)
    		scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].z);
    	printf("%d
    ", kruskal());
    	return 0;
    }
    
  • 相关阅读:
    树莓派配置
    《C#微信开发系列(Top)-微信开发完整学习路线》
    Git基础使用教程(仓库初始化,源码clone,源码push)
    《Cron表达式详解》
    《CSS实现单行、多行文本溢出显示省略号》
    《C#多线程编程实现方式》
    《SQLServer删除重复数据的方法》
    《java提高数据导入效率优化思路》
    《如何使用Javascript判断浏览器终端设备》
    《动手实现一个网页加载进度loading》
  • 原文地址:https://www.cnblogs.com/Salty-Fish/p/13386293.html
Copyright © 2020-2023  润新知