到了旱季农业生产的灌溉就成了一个大问题。为了保证灌溉的顺利,某县政府决定投资为各个村之间建立灌溉管道。
输入第1行包括一个整数N,表示某县的村庄的数量。(3≤N≤100),第2行-结尾为一个N×N的矩阵,表示每个村庄之间的距离。虽然在理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,他们限制在80个字符,因此,某些行会紧接着另一些行。当然,对角线将会是0,因为不会有线路从第i个村到它本身(任何两个村之间的距离都不大于100000)。
输出只有一个,为修建灌溉管道将所有村庄相连在一个灌溉系统里所需的最小管道长度。
样例输入
4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
样例输出
28
import java.util.ArrayList;
import java.util.Scanner;
public class Main{//Prim算法
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();//顶点数
ArrayList<Integer> S=new ArrayList<Integer>();//S集合(存储已经归并的顶点)
ArrayList<Integer> V=new ArrayList<Integer>();//V集合(存储还未归并的顶点)
ArrayList<Integer> C=new ArrayList<Integer>();//存储没归并一个顶点所用的最小耗费或最短路径
for (int i = 0; i <n; i++) {//初始化V集合
V.add(i);
}
S.add(0);//初始化S集合,从顶点0开始归并
int [][]c=new int[n][n];//用来存储一个顶点到另一个顶点的权值(一个村庄到另一个村庄的路径长度)
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
c[i][j]=sc.nextInt();//初始化
}
}
V.removeAll(S);//开始归并顶点前先去除S中顶点0(村庄0)
while(S.size()!=n){//只要S中顶点数不够n个(即没有将全部顶点加入),就继续归并顶点
int lowcost=Integer.MAX_VALUE;//最小耗费
Integer i = 0,j = 0;
//对S中的每一个顶点,求出其到V中每一个顶点的耗费(权值),如果比lowcost小,则更新lowcost,并记录当前最小耗费的边(i,j)
for (int v1 : S) {
for (int v2: V) {
if(c[v1][v2]!=0 && c[v1][v2]<lowcost){//如果c[v1][v2]==0,说明v1,v2这两个村庄之间没有路,不考虑在内
i=v1;
j=v2;
lowcost=c[v1][v2];
}
}
}
S.add(j);//归并顶点,将V中顶点j加入S中
V.remove(j);//同时要在V中删去顶点j
C.add(c[i][j]);//将这次归并的最小耗费(权值)加入到C集合中
}
int sum=0;
for (int cost : C) {
sum+=cost;
}
System.out.println(sum);//最小耗费
}
}