并查集,最小生成树

并查集

  字面意思就是几个集合的并集,和这个并集的查找。

  百度百科:并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,

  然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。

  在博客上,看到一篇很生动的文章,关于并查集的。看了它,也就基本知道并查集的求法了https://blog.csdn.net/u013546077/article/details/64509038

最小生成树:

  一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。

  最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。 [2

  Prim算法:

  1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
  2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
  3).重复下列操作,直到Vnew = V:
  a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
  b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
  4).输出:使用集合Vnew和Enew来描述所得到的最小生成树
  HDU - 1233
  我做这道题目的时候,虽然明白了prim算法,但是不知道增加最小的边,后来用了一个时间复杂度O(N3)的算法,就是在添加新边的时候,从已有的点从头到尾遍历,结果超时了。
  后来知道可以用贪心的思想,很快就写出来了。
  代码实现如何:
import java.util.Arrays;
import java.util.Scanner;

public class Main
{
    static final int MAX = 105;
    static final int INF = 1000005;
    static int dis[][] = new int[MAX][MAX];
    static int mid[] = new int[MAX];
    static boolean vis[] = new boolean[MAX];
    public static void main(String []args)
    {
        Scanner cin = new Scanner(System.in);
        while(true)
        {
            int N = cin.nextInt();
            if(N == 0)
            {
                return;
            }
            else if(N == 1)
            {
                System.out.println(0);
                continue;
            }
            Arrays.fill(vis, false);
            int M = N*(N-1)/2;
            for(int i = 0; i < M; i++)
            {
                int a,b,c;
                a = cin.nextInt();
                b = cin.nextInt();
                c = cin.nextInt();
                dis[a][b] = c;
                dis[b][a] = c;
            }
            System.out.println(Prim(N));
        }
    }
    static int Prim(int N)
    {
        int sum = 0;
        mid[1] = 0;
        for(int i = 2; i <= N; i++)
        {
            mid[i] = dis[1][i];
            if(dis[1][i] == 0)
            {
                mid[i] = INF;
            }
        }
        vis[1] = true;
        for(int i = 2; i <= N; i++)
        {
            int Min = INF;
            int temp = 0;
            for(int j = 2; j <= N; j++)
            {
                if(vis[j] == false && Min > mid[j])
                {
                    Min = mid[j];
                    temp = j;
                }
            }
            vis[temp] = true;
            sum += Min;
            for(int j = 2; j <= N; j++)
            {
                if(vis[j] == false && mid[temp]+dis[temp][j] < mid[j])
                {
                    mid[j] = mid[temp]+dis[temp][j];
                }
            }
        }
    }
}

  kruskal算法的实现过程,有自己去实践了!

 
 

  

原文地址:https://www.cnblogs.com/674001396long/p/9984808.html