CCF 201812-4:数据中心

试题编号:201812-4
试题名称:数据中心
时间限制:1.0s
内存限制:512.0MB
问题描述:


样例输入

4
5
1
1 2 3
1 3 4
1 4 5
2 3 8
3 4 2

样例输出

4

样例说明

  下图是样例说明。

 

试题分析

这个题目最麻烦的地方显然是读不懂题。圈重点:1.根据网络的定义,每个节点可以接受多个节点的信息,但是每个节点不能向多个节点发送信息,因此这个网络图应该是一棵树。2. 要求传输时间最短,因此这棵树的每条边权重之和应该是最小的。 3. 读懂Tmax的定义,其实就是这棵最小生成树的最大边的权重。

综上所述,我们要求的就是给定图的最小生成树的最大边的权重。

说到这里,题目的解法就很明确了。解决最小生成树问题常用的两种算法是Prim算法和Kruskal算法,在这里采用Kruskal算法解决这个问题。

1. 将所有边的权重按照从小到大进行排序。

2. 按照从小到大的顺序使用上述边连接对应的节点,前提是这些边不能形成回路,如果形成回路,则需要跳过这条边。

3. 假设有n个节点,输出第n-1个被加入的边的权重,这也就是最小生成树的最大边的权重。

在判断加入的边是否会形成回路方面,使用并查集算法来做这项任务,有关并查集的教程可以在coursera上学习普林斯顿的算法课程,本文中的代码使用的就是普林斯顿的课程提供的并查集代码。

代码

这份代码在CCF的评测系统上有的时候是100,有的时候会导致运行超时。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;

public class Main {

    public class WeightedQuickUnionUF {
        private int[] parent;
        private int[] size;

        public WeightedQuickUnionUF(int n) {
            parent = new int[n];
            size = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                size[i] = 1;
            }
        }

        public int find(int p) {
            while (p != parent[p])
                p = parent[p];
            return p;
        }

        public boolean connected(int p, int q) {
            return find(p) == find(q);
        }
        public void union(int p, int q) {
            int rootP = find(p);
            int rootQ = find(q);
            if (rootP == rootQ) return;

            if (size[rootP] < size[rootQ]) {
                parent[rootP] = rootQ;
                size[rootQ] += size[rootP];
            }
            else {
                parent[rootQ] = rootP;
                size[rootP] += size[rootQ];
            }
        }

    }

    class Vertex2Vertex implements Comparable<Vertex2Vertex>{
        public int vertex1;
        public int vertex2;
        public int weight;

        public Vertex2Vertex(int vertex1, int vertex2, int weight) {
            this.vertex1 = vertex1;
            this.vertex2 = vertex2;
            this.weight = weight;
        }

        @Override
        public int compareTo(Vertex2Vertex o) {
            if(this.weight>o.weight){
                return 1;
            }
            else{
                return -1;
            }
        }
    }

    public void run(){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        in.nextInt();
        WeightedQuickUnionUF uf = new WeightedQuickUnionUF(n);
        Vertex2Vertex[] elements = new Vertex2Vertex[m];
        for(int i=0;i<m;i++){
            int vertex1 = in.nextInt()-1;
            int vertex2 = in.nextInt()-1;
            int weight = in.nextInt();
            elements[i] = new Vertex2Vertex(vertex1,vertex2,weight);
        }
        Arrays.sort(elements);
        int max_weight = 0;
        int counter = 0;
        for(Vertex2Vertex e:elements){
            if(counter==n-1)
                break;
            if(!uf.connected(e.vertex1,e.vertex2)){
                uf.union(e.vertex1,e.vertex2);
                counter+=1;
                if(e.weight>max_weight){
                    max_weight=e.weight;
                }
            }
        }
        System.out.print(max_weight);
    }

    public static void main(String[] args) {
        new Main().run();
    }

}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值