1. 程式人生 > 實用技巧 >【堆】C003_AW_接水問題(暴力 / 堆)

【堆】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)\)