【java】最小生成树
来源:互联网 发布:php 数组的数组 编辑:程序博客网 时间:2024/06/03 19:23
航海家们在太平洋上发现了几座新岛屿,其中最大的一个岛已经连接到Internet,但是其它岛和主岛之间没有电缆连接,所以无法入网。我们的目的是让所有岛上的居民都能上网,即每个岛和主岛之间都有直接或间接的电缆连接。输入每两个岛屿之间的连接成本,要求给出最节省成本的方案。
先输入点的数量n,边的数量m,然后输入m行数据,每行数据包括起点u,终点v,成本weight,最后输出最优方案所选的边;
样例输入:
7 110 1 7
0 3 5
1 2 8
1 3 9
1 4 7
2 4 5
3 4 15
3 5 6
4 5 8
4 6 9
5 6 11
样例输出:
0 3 5
2 4 5
3 5 6
0 1 7
1 4 7
4 6 9
分析:本题的本质是无向图求最小生成树MST(Minimal Spanning Tree)。构造最小生成树的方法有很多,常见的有两个:Kruskal算法和Prim算法。
Kruskal算法
算法的第一步是把所有的边按权值从小到大排序,接下来依次遍历每条边(u,v),分两种情况:
情况1:最小生成树中已经包含u和v,则跳过;
情况2:最小生成树不包含u或v,则加入该边。
性质:如果(u,v)的权值是所有边中最小的,则最小生成树一定包含该边。可用反正法证明,若不加入该边,那么对于没有该边的最优解T,加入该边将有一个环,该环中至少有一条边的权值比(u,v)大,因此加入(u,v)一定是最优的。
算法伪代码:
把所有边排序,记第i小的边为e[i]初始化MST为空for(int i=0;i<m;i++){初始化连通分量,让每个点自成一个独立的连通分量 if(e[i].u或e[i].v不在同一个连通分量中){ 把e[i]加入MST 合并e[i].u和e[i].v所在的连通分量 }}
在算法实现中,边的排序可直接使用库函数,判断两个点是否在同一个连通分量中,可使用并查集方法。
并查集:把每个连通分量看成一个集合,该集合包含了连通分量中的所有点,每个连通分量用树来表示该集合,每棵树的根节点是这棵树的代表元。
如果两个节点所在树的根节点相同,则代表这两个点在同一个连通分量中。使用路径压缩可加快遍历过程。
import java.util.Arrays; import java.util.Scanner; class Edge implements Comparable<Edge>{ int u; int v; int weight; Edge(int u,int v,int weight){ this.u=u; this.v=v; this.weight=weight; } public int compareTo(Edge e) { if(weight>e.weight) return 1; else if(weight<e.weight) return -1; return 0; } } public class Main {public static int find(int[] p,int x){if(p[x]==x)return x;else return p[x]=find(p,p[x]); //查询父节点} public static void main(String[] args){ Scanner scanner = new Scanner(System.in); while(scanner.hasNext()){ int n=scanner.nextInt(); int m=scanner.nextInt(); Edge[] edges=new Edge[m]; for(int i=0;i<m;i++){ int u=scanner.nextInt(); int v=scanner.nextInt(); int weight=scanner.nextInt(); edges[i]=new Edge(u,v,weight); } Arrays.sort(edges); int[] p=new int[n]; for(int i=0;i<n;i++)//初始化连通分量,每个点自成一个连通分量 p[i]=i; for(int i=0;i<m;i++){ int x=find(p,edges[i].u); int y=find(p,edges[i].v); if(x==y){ continue; }else{ p[x]=y; System.out.println(edges[i].u+" "+edges[i].v+" "+edges[i].weight); } } } scanner.close(); } }
Prim算法
Prim算法
把点分成两个集合,A为已选中(已经在最小生成树中)的顶点,B未选中的顶点,循环n次,每次都是选择是跨越这两个集合最小的边。
先输入点的数量n,边的数量m,然后输入m行数据,每行数据包括起点u,终点v,成本weight,最后输出最小生成树的总权值;
样例输入:
7 11
0 1 7
0 3 5
1 2 8
1 3 9
1 4 7
2 4 5
3 4 15
3 5 6
4 5 8
4 6 9
5 6 11
样例输出:
39
import java.util.Arrays;import java.util.Scanner;public class Main {public static void main(String[] args){Scanner scanner = new Scanner(System.in);while(scanner.hasNext()){int n=scanner.nextInt();int m=scanner.nextInt();int[][] edges=new int[n][n];for(int i=0;i<m;i++){int u=scanner.nextInt();int v=scanner.nextInt();int weight=scanner.nextInt();edges[u][v]=weight;edges[v][u]=weight;}int[] dist=new int[n];//dist[i]存放结点i到已访问结点的最小权值Arrays.fill(dist, Integer.MAX_VALUE);dist[0]=0;int[] visited=new int[n];int result=0;for(int i=0;i<n;i++){//循环n次,每次选出一个点加入到最小生成树int x=-1,min=Integer.MAX_VALUE;for(int j=0;j<n;j++){//选出未访问的结点中dist最小的结点if(visited[j]==0&&dist[j]<min){x=j;min=dist[j];}}result+=min;visited[x]=1;for(int k=0;k<n;k++){//更新dist值if(visited[k]==0&&edges[x][k]>0){if(dist[k]>edges[x][k])dist[k]=edges[x][k];}}}System.out.println(result);}scanner.close();}}
Prim算法和Dijkstra算法的异同
相同点:
二者都是采用贪心策略,代码结构类似;
不同点:
①Prim算法用于无权图生成最小生成树,Dijkstra算法用于无权图/带权图的单源最短路径。
②Prim算法中,dist数组保存的是结点i到已访问结点的最小权值;相应地,更新过程是dist[k]=edges[x][k];
Dijkstra算法中,dist数组保存的是源结点到结点i的最短路径长度;相应地,更新过程是dist[k] = dist[x]+edges[x][k];
③Prim算法可以任选一个顶点作为起点,Dijkstra算法要有一个确定的起点。
- 【java】最小生成树
- java数据结构 最小生成树
- JAVA-prim 最小生成树
- 最小生成树prim java 实现
- JAVA版最小生成树算法
- Java实现最小生成树Kruskal算法
- prim 最小生成树算法 java实现
- Kruskal算法计算最小生成树(java)
- 最小生成树(java实现)
- JAVA的最小生成树(prim)算法
- java中最小生成树的实现
- JAVA实践最小生成树---kruskal算法
- JAVA实践最小生成树-Prim算法
- 最小生成树之java实现
- Graph java 实现最小生成树
- 最小比例 最小生成树
- 最小生成树&&次最小生成树
- 最小生成生成树计数
- 从url到页面展现,这之中发生了什么?
- MySQL游标的简单实践
- WinDbg 工具 Win10 系统下设置
- mongodb 3.4 配置文件启动
- dataGrid.ItemContainerGenerator.ContainerFromIndex(i)返回为空
- 【java】最小生成树
- plsql登陆及数据库char类型问题
- 微信小程序框架
- essential-copying and pasting from Stack Overflow原文和翻译
- IARforMSP"Fatal Error[Cp001]: Copy protection check, No valid license found for this product [24] ".
- Python 2.7 好玩游戏的物品清单
- 使用weinre真机调试移动web应用(转载)
- gets()和puts()函数
- Yeelink初步体验