zoukankan      html  css  js  c++  java
  • java实现第六届蓝桥杯灾后重建

    灾后重建

    题目描述
    Pear市一共有N(<=50000)个居民点,居民点之间有M(<=200000)条双向道路相连。这些居民点两两之间都可以通过双向道路到达。这种情况一直持续到最近,一次严重的地震毁坏了全部M条道路。
    震后,Pear打算修复其中一些道路,修理第i条道路需要Pi的时间。不过,Pear并不打算让全部的点连通,而是选择一些标号特殊的点让他们连通。
    Pear有Q(<=50000)次询问,每次询问,他会选择所有编号在[l,r]之间,并且 编号 mod K = C 的点,修理一些路使得它们连通。由于所有道路的修理可以同时开工,所以完成修理的时间取决于花费时间最长的一条路,即涉及到的道路中Pi的最大值。

    你能帮助Pear计算出每次询问时需要花费的最少时间么?这里询问是独立的,也就是上一个询问里的修理计划并没有付诸行动。

    【输入格式】
    第一行三个正整数N、M、Q,含义如题面所述。
    接下来M行,每行三个正整数Xi、Yi、Pi,表示一条连接Xi和Yi的双向道路,修复需要Pi的时间。可能有自环,可能有重边。1<=Pi<=1000000。

    接下来Q行,每行四个正整数Li、Ri、Ki、Ci,表示这次询问的点是[Li,Ri]区间中所有编号Mod Ki=Ci的点。保证参与询问的点至少有两个。

    【输出格式】
    输出Q行,每行一个正整数表示对应询问的答案。

    【样例输入】
    7 10 4
    1 3 10
    2 6 9
    4 1 5
    3 7 4
    3 6 9
    1 5 8
    2 7 4
    3 2 10
    1 7 6
    7 6 9
    1 7 1 0
    1 7 3 1
    2 5 1 0
    3 7 2 1

    【样例输出】
    9
    6
    8
    8

    【数据范围】
    对于20%的数据,N,M,Q<=30
    对于40%的数据,N,M,Q<=2000
    对于100%的数据,N<=50000,M<=2*10^5,Q<=50000. Pi<=10^6. Li,Ri,Ki均在[1,N]范围内,Ci在[0,对应询问的Ki)范围内。

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 5000ms

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
    注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
    注意:主类的名字必须是:Main,否则按无效代码处理。

    import java.util.ArrayList;
    import java.util.Scanner;
    
    public class Main {
        //使用Prim算法,获取输入图的最小生成树
        public int[][] getPrim(int[][] value) {
            int[][] result = new int[value.length][value[0].length]; //存放最终最小生成树的边权值
            int[] used = new int[value.length];  //用于判断顶点是否被遍历  
            for(int i = 1, len = value.length;i < len;i++)
                used[i] = -1;   //初始化,所有顶点均未被遍历
            used[1] = 1;  //从顶点1开始遍历,表示顶点已经被遍历
            
            int count = 1;    //记录已经完成构造最小生成树的顶点
            int len = value.length;
            while(count < len) {  //当已经遍历的顶点个数达到图的顶点个数len时,退出循环
                int tempMax = Integer.MAX_VALUE;
                int tempi = 0;
                int tempj = 0;
                for(int i = 1;i < len;i++) {  //用于遍历已经构造的顶点
                    if(used[i] == -1)  
                        continue;
                    for(int j = 1;j < len;j++) {  //用于遍历未构造的顶点
                        if(used[j] == -1) {
                            if(value[i][j] != 0 && tempMax > value[i][j]) {
                                tempMax = value[i][j];
                                tempi = i;
                                tempj = j;
                            }
                        }
                    }
                }
                result[tempi][tempj] = tempMax;
                result[tempj][tempi] = tempMax;
                used[tempj] = 1;
                count++;
            }
            return result;
        }
        //使用floyd算法获取所有顶点之间的最短路径的具体路径
        public void floyd(int[][] primTree, int[][] path) {
            int[][] tree = new int[primTree.length][primTree.length];
            for(int i = 1;i < primTree.length;i++) 
                for(int j = 1;j < primTree.length;j++)
                    tree[i][j] = primTree[i][j];
            for(int k = 1;k < primTree.length;k++) {
                for(int i = 1;i < primTree.length;i++) {
                    for(int j = 1;j < primTree[0].length;j++) {
                        if(tree[i][k] != 0 && tree[k][j] != 0) {
                            int temp = tree[i][k] + tree[k][j];
                            if(tree[i][j] == 0) {
                                tree[i][j] = temp;
                                path[i][j] = k;   //存放顶点i到顶点j之间的路径节点
                            }
                                
                        }
                    }
                }
            }
        }
        //返回a与b之间的最大值
        public int max(int a, int b) {
            return a > b ? a : b;
        }
        //根据最短路径,返回顶点start~end之间的最大权值边
        public int dfsMax(int[][] primTree, int[][] path, int start, int end) {
            if(path[start][end] == 0)
                return primTree[start][end];
            int mid = path[start][end];  //start和end的中间顶点
            return max(dfsMax(primTree, path, start, mid), dfsMax(primTree, path, mid, end));
        }
        //根据最小生成树,返回各个顶点到其它顶点行走过程中,权值最大的一条边
        public int[][] getMaxValue(int[][] primTree) {
            int[][] path = new int[primTree.length][primTree[0].length];
            floyd(primTree, path);       //获取具体最短路径
            int[][] result = new int[primTree.length][primTree[0].length];
            for(int i = 1;i < primTree.length;i++) {
                for(int j = 1;j < primTree.length;j++) {
                    if(j == i)
                        continue;
                    int max = dfsMax(primTree, path, i, j);
                    result[i][j] = max;
                }
            }
            return result;
        }
        //打印出题意结果
        public void printResult(int[][] value, int[][] result) {
            int[][] primTree = getPrim(value);      //获取输入图的最小生成树
            int[][] maxResult = getMaxValue(primTree);    //获取各个顶点到其它顶点最短路径中最大权值边
            for(int i = 0;i < result.length;i++) {
                int L = result[i][0];
                int R = result[i][1];
                int K = result[i][2];
                int C = result[i][3];
                ArrayList<Integer> list = new ArrayList<Integer>();
                for(int j = L;j <= R;j++) {
                    if(j % K == C)
                        list.add(j);
                }
                int max = 0;
                for(int j = 0;j < list.size();j++) {
                    for(int k = j + 1;k < list.size();k++) {
                        if(max < maxResult[list.get(j)][list.get(k)])
                            max = maxResult[list.get(j)][list.get(k)];
                    }
                }
                System.out.println(max);
            }
            return;
        }
        
        public static void main(String[] args) {
            Main test = new Main();
            Scanner in = new Scanner(System.in);
            int N = in.nextInt();
            int M = in.nextInt();
            int Q = in.nextInt();
            int[][] value = new int[N + 1][N + 1];
            for(int i = 1;i <= M;i++) {
                int a = in.nextInt();
                int b = in.nextInt();
                int tempV = in.nextInt();
                value[a][b] = tempV;
                value[b][a] = tempV;
            }
            int[][] result = new int[Q][4];
            for(int i = 0;i < Q;i++) {
                result[i][0] = in.nextInt();
                result[i][1] = in.nextInt();
                result[i][2] = in.nextInt();
                result[i][3] = in.nextInt();
            }
            test.printResult(value, result);
        }
    }
    
  • 相关阅读:
    android学习地址
    Android获取屏幕高度、标题高度、状态栏高度详解
    学习地址(杂)
    获取控制台应用程序自己的文件名
    学习地址
    如何分配数据库角色权限
    android 近百个源码项目
    深入理解默认构造函数
    深入理解拷贝构造函数
    读权限和执行权限的差别
  • 原文地址:https://www.cnblogs.com/a1439775520/p/13077332.html
Copyright © 2011-2022 走看看