【堆】C003_AW_接水问题(暴力 / 堆)

学校里有一个水房,水房里一共装有 m 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为 1。  
现在有 n 名同学准备接水,他们的初始接水顺序已经确定。
将这些同学按接水顺序从 1 到 n 编号,i 号同学的接水量为 wi。
接水开始时,1 到 m 号同学各占一个水龙头,并同时打开水龙头接水。
当其中某名同学 j 完成其接水量要求 wj 后,下一名排队等候接水的同学 k 马上接替 j 同学的位置开始接水。
这个换人的过程是瞬间完成的,且没有任何水的浪费。
即 j 同学第 x 秒结束时完成接水, 则 k 同学第 x+1 秒立刻开始接水。 
若当前接水人数 n’ 不足 m,则只有 n’ 个龙头供水,其它 m−n’ 个龙头关闭。  
现在给出 n 名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。
输入格式
第 1 行 2 个整数 n 和 m,用一个空格隔开,分别表示接水人数和龙头个数。 
第 2 行 n 个整数 w1、w2、…、wn,每两个整数之间用一个空格隔开,wi表示 i 号同学的接水量。
输出格式
输出只有一行,1 个整数,表示接水所需的总时间。
数据范围
对于 30%的数据,n≤10,000,m≤1,000;
对于全部的数据,1≤m≤n≤1,000,000,1≤m≤100,000

输入样例:
5 3
4 4 1 2 1
输出样例:
4

方法一:暴力

在 O(n) 循环中嵌套一个 O(m) 循环取找 m 个水龙头中最早处于闲置状态的水龙头,则下一个同学一定会选用该水龙头装水


复杂度分析

  • Time\(O(nm)\)
  • Space\(O(1)\)

方法二:堆

用堆来优化掉 O(m) 时间,先让前m个同学取接水(放入小根堆中),下一个人的接水时间就是 A[i]+q.top()(i∈[m+1, n)),记录过程中的最大接水时间就是答案

import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
    static class Solution {
        void init() throws IOException {
            Scanner sc = new Scanner(new BufferedInputStream(System.in));
            String[] t = sc.nextLine().split(" ");
            int n=Integer.parseInt(t[0]), m=Integer.parseInt(t[1]), A[]=new int[n];
            for (int i=0; i<n; i++) { A[i]=sc.nextInt(); }
            int ans=0;
            Queue<Integer> q = new PriorityQueue<>();
            for (int i=0; i<m; i++) {
                if (A[i]>ans) ans=A[i];
                q.add(A[i]);
            }
            for (int i=m; i<n; i++) {
                int nx=q.poll()+A[i];
                if (nx>ans) ans=nx;
                q.add(nx);
            }
            System.out.println(ans);
        }
    }
    public static void main(String[] args) throws IOException {  
        Solution s = new Solution();
        s.init();
    }
}

复杂度分析

  • Time\(O(nlogm)\)
  • Space\(O(m)\)
原文地址:https://www.cnblogs.com/wdt1/p/13656281.html