• Kruskal和Prim算法求最小生成树


    Kruskal算法求最小生成树

    测试数据:
    5 6
    0 1 5
    0 2 3
    1 2 4
    2 4 2
    2 3 1
    1 4 1

    输出:
    2 3 1
    1 4 1
    2 4 2
    0 2 3

    思路:在保证不产生回路的情况下,选择权值小的边。是否产生回路采用并查集来实现

    判断两个点是否连通:如果两个点的祖先不是同一个,说明这两个点不可联通,要标志两个点联通,只要使两个点的祖先是同一个。关于并查集的讲解可以看我转载的一篇文章。

    比如初始化的时候ABC的祖先是他自己,先加入了AB这条边,这两个点的的父亲不一样,可以加入这条边,同时将A的祖先设置为B的祖先。同样AC加入也是这样,将C的父亲设为A的祖先B。这时候发现ABC相互可达,他们的祖先都是一个B。这个时候如果要添加BC这条边,查看BC的祖先,发现祖先一样,说明这两个点是可达的,那么如果添加这条边就会产生回路。

    总的来说,将相邻的边所有顶点的祖先设置为同一个,如果两个顶点的祖先是同一个,那么就表明这两个点是可达的。那么如果还要添加这个以这两个顶点为顶点的边,就会产生回路。

    import java.io.BufferedReader;
    import java.io.FileReader;
    public class Kruskal {
    	static int father[];
    	static Edge edges[];
    	static Edge tree[];
    	static int verNum,edgeNum;
    	public static void main(String[] args) throws Exception {
    		
    		readData();
    		initFather();
    		getTree();
    	}
    	/**
    	 * 读取文本的数据
    	 * @throws Exception
    	 */
    	private static void readData()throws Exception {
    		// TODO 自动生成的方法存根
    		BufferedReader bf=new BufferedReader(new FileReader("d:/testGraphic.txt"));
    		String strings[]=bf.readLine().split(" ");
    		verNum=Integer.parseInt(strings[0]);
    		edgeNum=Integer.parseInt(strings[1]);
    		edges=new Edge[edgeNum];
    		tree=new Edge[verNum-1];
    		for (int i = 0; i < edgeNum; i++) {
    			strings=bf.readLine().split(" ");
    			edges[i]=new Edge(Integer.parseInt(strings[0]),Integer.parseInt(strings[1]),Integer.parseInt(strings[2]));
    		}
    		sort();
    		bf.close();
    	}
    	/**
    	 * 将各条边按照权值从小到大进行排列
    	 */
    	public static void sort()
    	{
    		for (int i = 0; i < edges.length; i++) {
    			for (int j = i+1; j < edges.length; j++) {
    				if(edges[j].weight<edges[i].weight)
    				{
    					Edge temp=edges[j];
    					edges[j]=edges[i];
    					edges[i]=temp;
    				}
    			}
    		}
    	}
    	/**
    	 * 初始化每个点的父亲设置为自己
    	 */
    	private static void initFather() {
    		// TODO 自动生成的方法存根
    		father=new int[verNum];
    		for (int i = 0; i < father.length; i++) {
    			father[i]=i;
    		}
    	}
    	/**
    	 * 获得最小生成树
    	 */
    	private static void getTree() {
    		// TODO 自动生成的方法存根
    		int edgesIndex=0;
    		int treeIndex=0;
    		while(true)
    		{
    			//如果边数够了跳出循环
    			if(treeIndex==verNum-1)
    				break;
    			int father1=findFather(edges[edgesIndex].from);
    			int father2=findFather(edges[edgesIndex].end);
    			//如果两个的点的父亲不相同 则说明不连通
    			if(father1!=father2)
    			{
    				tree[treeIndex++]=edges[edgesIndex];
    				
    				father[father1]=father2;
    			}
    			edgesIndex++;
    		}
    		//输出树
    		printTree();
    	}
    	private static void printTree() {
    		// TODO 自动生成的方法存根
    		for (int i = 0; i < tree.length; i++) {
    			Edge edge=tree[i];
    			System.out.println(edge);
    		}
    	}
    	
    
    	/**
    	 * 查找一个点的父亲
    	 * @param i
    	 * @return
    	 */
    	public static int findFather(int i)
    	{
    		//如果一个点的父亲是自己 返回
    		if(father[i]==i)
    			return i;
    		//否则一直查找他的顶层。
    		else
    		{
    			int f=i;
    			while(father[f]!=f)
    			{
    				f=father[f];
    			}
    			
    			father[i]=father[f];
    			return father[f];
    		}
    	}
    	
    }
    class Edge
    {
    	public int from;
    	public int end;
    	public int weight;
    	public Edge(int from,int end,int weight)
    	{
    		this.from=from;
    		this.end=end;
    		this.weight=weight;
    	}
    	public String toString()
    	{
    		return this.from+" "+this.end+" "+this.weight;
    	}
    }
    

    prim算法求最小生成树

    思路:先随机找一个点添加到点集U中,在V-U中找一个点与U点集中关联并且权值最小的点,然后将这个点添加到点集U中,依次下去,直至U==V

    测试数据:
    5 6
    0 2 3
    1 2 4
    2 4 2
    2 3 1
    1 4 1

    输出:
    0 2 3
    2 3 1
    2 4 2
    4 1 1

    import java.io.BufferedReader;
    import java.io.FileReader;
    
    public class Prime {
    	static int array[][];
    	static int verNum,edgeNum;
    	/**
    	 * 读取文本数据
    	 * @throws Exception
    	 */
    	public static void readData() throws Exception
    	{
    		BufferedReader bf=new BufferedReader(new FileReader("d:/testGraphic.txt"));
    		String strings[]=bf.readLine().split(" ");
    		verNum=Integer.parseInt(strings[0]);
    		edgeNum=Integer.parseInt(strings[1]);
    		array=new int [verNum][verNum];
    		//用矩阵表示两个点之间的权值,如果是相同点标志为0 如果两个点不关联设为100
    		for (int i = 0; i < array.length; i++) {
    			for (int j = 0; j < array.length; j++) {
    				if(i==j)
    					array[i][j]=0;
    				else
    					array[i][j]=100;
    			}
    		}
    		
    		//根据文本进行赋值
    		for (int i = 0; i < edgeNum; i++) {
    			strings=bf.readLine().split(" ");
    			int a=Integer.parseInt(strings[0]);
    			int b=Integer.parseInt(strings[1]);
    			int c=Integer.parseInt(strings[2]);
    			array[a][b]=c;
    			array[b][a]=c;
    		}
    			
    	}
    	/**
    	 * 打印生成最小树
    	 * @param tree
    	 */
    	public static void printTree(int tree[][])
    	{
    		for(int a[]:tree)
    		{
    			for(int b:a)
    			{
    				System.out.print(b+" ");
    			}
    			System.out.println();
    		}
    	}
    	public static void main(String[] args) throws Exception 
    	{
    		readData();
    		//创建最小生成树
    		int tree[][]=new int [verNum-1][3];
    		
    		//取一个点放到点集U
    		int k=0;
    		
    		CloseEdge edge[]=new CloseEdge[verNum];
    		//其他点和点K的权值
    		for (int i = 0; i < verNum; i++) {
    			edge[i]=new CloseEdge(k,array[k][i]);
    		}
    		edge[k]=new CloseEdge(k,0);
    		
    		//执行次数为边的数量
    		for (int o = 0; o< verNum-1; o++) 
    		{
    			int min=Integer.MAX_VALUE;
    			//在V-U中的点中找一个和U中点关联的并且权值最小的加入到U
    			for (int i = 0; i <verNum; i++) {
    				if(edge[i].weight!=0&&edge[i].weight<min)
    				{
    					min=edge[i].weight;
    					k=i;
    				}
    			}
    			//将新选取点的权值存到数中
    			tree[o][2]=edge[k].weight;
    			//设置选中的点到U的权值为0,表示已经在U中
    			edge[k].weight=0;
    			
    			//将新增加的变记录下来,第0个点是与新顶点相关联的的点,第一个顶点是新的顶点
    			tree[o][0]=edge[k].index;
    			tree[o][1]=k;
    			
    			
    			
    			//因为有新顶点加入,所以重新设置V-U与点集U中点关联的最小的权值
    			for (int i = 0; i < edge.length; i++) {
    				if(array[k][i]<edge[i].weight)
    					edge[i]=new CloseEdge(k,array[k][i]);
    			}
    		}
    		printTree(tree);
    		
    		
    	}
    }
    
    class CloseEdge
    {
    	
    	
    	
    	int index;
    	int weight;
    	/**
    	 * 
    	 * @param index
    	 * @param weight
    	 */
    	public CloseEdge(int index,int weight)
    	{
    		this.index=index;
    		this.weight=weight;
    	}
    }
    
  • 相关阅读:
    2019年春季学期第三周作业
    2019年春季学期第二周作业
    7-2 求最大值及其下标 (20 分)
    7-1 查找整数 (10 分)
    人生中最重要的三位老师
    自我介绍
    学期总结
    编程作业 抓老鼠啊~亏了还是赚了?
    作业——10
    作业——9
  • 原文地址:https://www.cnblogs.com/-new/p/6762670.html
Copyright © 2020-2023  润新知