Smallest Ship Capacity for D Days

medium Searching and Sorting

Problem

Packages with the given weights must be shipped in the same order, one ship trip per day. Each day the ship carries a continuous part of the list and its total weight must not be more than the ship capacity. Print the smallest capacity that ships all packages within D days. Input: n, the weights, then D.

Constraints

  • 1 <= n <= 10^4
  • 1 <= weight <= 500
  • 1 <= D <= n

Examples

Input

10
1 2 3 4 5 6 7 8 9 10
5

Output

15

Solutions

Best approachTime O(n log(sum))Space O(1)

We do not search the array. We search the capacity. If a capacity works, every bigger capacity works too, so binary search can cut the range in half. Each test is one O(n) pass.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Smallest capacity.
 * Input   : n, the weights, then D.
 * Output  : The capacity.
 * Approach: Binary search on the answer.
 * Time    : O(n log(sum))
 * Space   : O(1)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Count the days needed when the ship can carry "capacity" per day.
        private static int daysNeeded(int[] a, long capacity) {
            int days = 1;
            long current = 0;
            for (int weight : a) {
                if (current + weight > capacity) {
                    days++;
                    current = 0;
                }
                current += weight;
            }
            return days;
        }

    // This method solves the task. It receives the input and returns the answer.
    static long solve(int[] a, int k) {
        // Step 1: The capacity is at least the heaviest package and at most the total weight.
        long low = 0;
        long high = 0;
        for (int weight : a) {
            low = Math.max(low, weight);
            high += weight;
        }
        // Step 2: Binary search on the answer. A bigger capacity never needs more days, so the test is monotone.
        while (low < high) {
            long middle = low + (high - low) / 2;
            if (daysNeeded(a, middle) <= k) {
                high = middle;
            } else {
                low = middle + 1;
            }
        }
        return low;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int size = scanner.nextInt();
        int[] a = new int[size];
        for (int i = 0; i < size; i++) {
            a[i] = scanner.nextInt();
        }
        int k = scanner.nextInt();
        System.out.println(solve(a, k));
    }
}
Hints (2)
  1. Why is the answer at least the heaviest package?
  2. What does it mean if daysNeeded is too big?