牛客网——继续畅通工程

题目描述

    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。

输入描述:

    测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。

    当N为0时输入结束。

输出描述:

    每个测试用例的输出占一行,输出全省畅通需要的最低成本。

链接:https://www.nowcoder.com/questionTerminal/16212f7d46e44174b5505997ea998538
来源:牛客网

import java.util.Scanner;
import java.util.Arrays;
import java.util.Comparator;
 
class edge{
    private int u;
    private int v;
    private int w;
     
    public edge(int u, int v, int w) {
        this.u = u;
        this.v = v;
        this.w = w;
    }
    public int getU() {
        return u;
    }
    public int getV() {
        return v;
    }
    public int getW() {
        return w;
    }
    public void setW(int w){
        this.w = w;
    }
}
public class Main {
    static int f[] = new int[100];
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int n = input.nextInt();    //顶点数
        int m = n*(n-1)/2;    //边数
        edge e[] = new edge[m];
        for(int i=0;i<m;i++){
            int u = input.nextInt();
            int v = input.nextInt();
            int w = input.nextInt();
            e[i] = new edge(u,v,w);
            int status = input.nextInt();
            if(status == 1){
                e[i].setW(0);
            }
        }
        //按边的权值从小到大排序
        Arrays.sort(e, new Comparator<edge>(){
            public int compare(edge o1, edge o2) {
                if(o1.getW()>o2.getW()){
                    return 1;
                }else if(o1.getW()<o2.getW()){
                    return -1;
                }else{
                    return 0;
                }
            }
        });
        //并查集初始化,数组里存的是自己数组的下标编号
        for(int i=0;i<n;i++){
            f[i] = i;
        }
        //Kruskal算法核心部分
        int count = 0,sum = 0;
        for(int i=0;i<m;i++){        //从小到大枚举每一条边
            if(merge(e[i].getU(),e[i].getV())){        //判断两个点是否联通,不连通则用这条边
                count++;
                sum += e[i].getW();
            }
            if(count == n-1){
                break;
            }
        }
        System.out.println(sum);
    }
    //并查集合并两个子集合
    public static boolean merge(int u,int v){
        int t1 = getf(u);
        int t2 = getf(v);
        if(t1 != t2){    //判断两个点是否在同一个集合中
            f[t2] = t1;
            return true;
        }
        return false;
    }
    //并查集寻找祖先
    public static int getf(int v){
        if(f[v]==v){
            return v;
        }else{
            f[v] = getf(f[v]);        //路径压缩
            return f[v];
        }
    }
}

 

posted @ 2019-02-13 18:26  JAYPARK01  阅读(251)  评论(0编辑  收藏  举报