贪心算法之克鲁斯卡尔算法

贪心算法之克鲁斯卡尔算法_第1张图片


最小生成树性质:设G=(V,E)是一个连通网络,U是顶点集V的一个真子集。若(u,v)是G中一条“一个端点在U中(例如:u∈U),另一个端点不在U中的边(例如:v∈V-U),且(u,v)具有最小权值,则一定存在G的一棵最小生成树包括此边(u,v)。


该定理阐明的属性也被称之为切割属性,简单讲就是横跨该切割的权重最小的边,即一端在s,另一端v-s,这条边一定在某一颗最小生成树的一条边上


克鲁斯卡尔算法步骤:

 1.对所有边的权值进行递增排序,

 2.对于从小到大的每一条边,如果加入后不构成环就加入,反之排除在外,直到所有边判断完毕。【ps:算法时间取决于边的数目】


  下面是伪代码

 贪心算法之克鲁斯卡尔算法_第2张图片

  可以看到,2步操作执行的正是并查集的find union操作 


  算法的正确性证明:使用数学归纳法,针对顶点

1.n=2时,即只有两个点的时候,该算法显然成立,一次得结果

2.n>2时,假设2<=j

  假设这个边不在最小生成树上,那么存在一条边小于这个权值的一条边,显然它应该在之前被选出来,那样的话把它加入到这n-1个顶点中就构成了环,删除一条权值最大的边,就产生了一颗权值更小的n-1个顶点的最小生成树,这与条件相左,说明该方法是正确的


package org.kruskal;

import java.util.Scanner;

class Edge
{
	public int begin;
	
	public int end;
	
	public int weight;
}

class Graph
{
	public int vertexnum;
	
	public int edgenum;
	
	public Edge []edges;
	
	public int  []parent;
}



public class Kruskal {
	

	  public  int find (int i,int []array)
	    {
	    	while(array[i]!=i)
	    	{
	    		i=array[i];
	    	}
	    	return i;
	    }
	    
	    public void union(int i,int j,int []array)
	    {
	    	array[i]=j;
	    }
	    
	    public void KruskalInit(Graph g)
	    {
	    	Scanner input=new Scanner(System.in);
	    	System.out.println("input vertexnum and edgenum");
	    	g.vertexnum=input.nextInt();
	    	g.edgenum=input.nextInt();
	    	int parent[]=new int[g.vertexnum+1];
	    	Edge edges[]=new Edge[g.edgenum];
	    	for(int i=0;ig.edges[j+1].weight)
	    			{
	    				Edge edge=g.edges[j];
	    				g.edges[j]=g.edges[j+1];
	    				g.edges[j+1]=edge;
	    			}
	    		}
	    	}
	    }
	    
	    public void  KruskalCount(Graph g)
	    {
	    	this.KruskalInit(g);
	    	KruskalSort(g);
	    	int vertexnum=g.vertexnum-1;
	    	int sum=0;
	    	for(int i=0;i


 


你可能感兴趣的:([算法笔记])