zoukankan      html  css  js  c++  java
  • 学习记录:最小生成树

    最小生成树

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

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

    模板题: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;
    }
    
  • 相关阅读:
    mac os programming
    Rejecting Good Engineers?
    Do Undergrads in MIT Struggle to Obtain Good Grades?
    Go to industry?
    LaTex Tricks
    Convert jupyter notebooks to python files
    How to get gradients with respect to the inputs in pytorch
    Uninstall cuda 9.1 and install cuda 8.0
    How to edit codes on the server which runs jupyter notebook using your pc's bwroser
    Leetcode No.94 Binary Tree Inorder Traversal二叉树中序遍历(c++实现)
  • 原文地址:https://www.cnblogs.com/Salty-Fish/p/13386293.html
Copyright © 2011-2022 走看看