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

aa


最小生成树性质:设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:算法时间取决于边的数目】


  下面是伪代码

 bb

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


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

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

2.n>2时,假设2<=j<n,成立,即n-1顶点已经连通了,这是一颗n-1个顶点的最小生成树,后面选择权值最小的一条能联通n个顶点的边加入即构成最小生成树

  假设这个边不在最小生成树上,那么存在一条边小于这个权值的一条边,显然它应该在之前被选出来,那样的话把它加入到这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;i<edges.length;i++)
	    	{
	    		edges[i]=new Edge();
	    		System.out.println("input begin,end,weight");
	    		edges[i].begin=input.nextInt();
	    		edges[i].end=input.nextInt();
	    		edges[i].weight=input.nextInt();
	    	}
	    	for(int i=1;i<parent.length;i++)
	    	{
	    		parent[i]=i;
	    	}
	    	g.edges=edges;
	    	g.parent=parent;	    	
	    }
	    
	    public void  KruskalSort(Graph g)
	    {
	    	int edgenum=g.edgenum;
	    	for(int i=0;i<edgenum-1;i++)
	    	{
	    		for(int j=0;j<edgenum-i-1;j++)
	    		{
	    			if(g.edges[j].weight>g.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<g.edgenum&&vertexnum!=0;i++)
	    	{
	    		int n=find(g.edges[i].begin,g.parent);
	    		int m=find(g.edges[i].end,g.parent);
	    		if(n!=m)
	    		{
	    			union(n,m,g.parent);
	    			sum+=g.edges[i].weight;
	    			vertexnum--;
	    		}
	    	}
	    	if(vertexnum==0)
	    	{
	    		System.out.println("this is MiniSpanTree  Weight is "+sum);
	    	}
	    	else
	    	{
	    		System.out.println("error");
	    	}
	    }
	    
	    
	    public static void main(String args[])
	    {
	    	Kruskal k=new Kruskal();
	    	Graph g=new Graph();
	    	k.KruskalCount(g);
	    	
	    }
	
}


 


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值