zoukankan      html  css  js  c++  java
  • 搜索的应用-分配货物

    题目链接: http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_4_D

    You are given (n) packages of (w_i) kg from a belt conveyor in order ((i=0,1,...n−1)). You should load all packages onto (k) trucks which have the common maximum load (P). Each truck can load consecutive packages (more than or equals to zero) from the belt conveyor unless the total weights of the packages in the sequence does not exceed the maximum load (P).

    Write a program which reads (n), (k) and (w_i), and reports the minimum value of the maximum load (P) to load all packages from the belt conveyor.

    Input

    In the first line, two integers (n) and (k) are given separated by a space character. In the following (n) lines, (w_i) are given respectively.

    Output

    Print the minimum value of (P) in a line.

    Constraints
    • 1≤(n)≤100,000
    • 1≤(k)≤100,000
    • 1≤(w_i)≤10,000
    Sample Input 1
    5 3
    8
    1
    7
    3
    9
    
    Sample Output 1
    10
    

    If the first truck loads two packages of {8,1}, the second truck loads two packages of {7,3} and the third truck loads a package of {9}, then the minimum value of the maximum load (P) shall be 10.

    Sample Input 2
    4 2
    1
    2
    2
    6
    
    Sample Output 2
    6
    

    if the first truck loads three packages of {1,2,2} and the second truck loads a package of {6}, then the minimum value of the maximum load (P) shall be 6.

    题目大意是有(n)个包裹,每个包裹分别重(w_i),然后放在一个传送带上面。又有(k)辆卡车,每辆卡车的最大承重量都是一样的。现在要做的就是将这些包裹放在卡车上,求使最大承重量最小的值。这道题要注意的一点是,这些包裹是连续放在某一辆卡车上,等这辆卡车装满之后才放下一辆卡车。

    所以我们的解题思路大概是这样的,先假定一个最大承重量,然后将包裹一辆一辆卡车的放,即哪一辆卡车放满了,再放入下一辆。这个时候可能有两种情况,一种就是放完包裹了,卡车还空很多,这就有可能是我们的最大承重量大了,可以减小;还有就是包裹放不进去卡车了,这说明我们假设的最大承重量太小,应该增大。于是这道题的关键就在于最大承重量的假设上。我们可以按照限定条件给定的重量从低到高尝试,但是这种效率较低。于是我们考虑到二分搜索,提高效率。

    参考代码如下:

    import java.util.Scanner;
    
    public class Allocation {
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            int k = sc.nextInt();
            int[] weight = new int[n];
            for (int i=0; i<n; i++){
                weight[i] = sc.nextInt();
            }
    
            // 使用二分搜索假定最大承重量(solve)
            // n的限制范围为100,000,每个物品的范围限制为100,000,所以重量范围为1~10^10
            System.out.println(solve1(n, k, weight));
    
        }
    
        // 这个二分搜索左边是开区间,右边是闭区间,缩小区间时依然保持这种状态。在终止条件的判断时,如果最后只有一个元素才停止,即我们需要的元素
        private static long solve(int n, int k, int[] weight) {
            long left = 0;
            long rihgt = 100000 * 100000;
    
            while(rihgt-left > 1){
                long mid = (left+rihgt)/2;
                int temp = check(mid, n, k, weight);
                if (temp >= n){
                    rihgt = mid;
                }
                else {
                    left = mid;
                }
            }
    
            return rihgt;
        }
    
        // 另外一种二分搜索的写法。两边都是闭区间,终止条件为只有一个元素。
        private static long solve1(int n, int k, int[] weight) {
            long left = 1;
            long rihgt = 100000 * 100000;
    
            while(left < rihgt){
                long mid = (left+rihgt)/2;
                int temp = check(mid, n, k, weight);
                if (temp >= n){
                    rihgt = mid;
                }
                else {
                    left = mid+1;
                }
            }
    
            return rihgt;
        }
    
    
        private static int check(long p, int n, int k, int[] weight) {
    
            int i = 0;
    
            for (int j=0; j<k; j++){
                long s = 0;
                while (s+weight[i] <= p){
                    s += weight[i];
                    i++;
                    if (i == n){
                        return n;
                    }
                }
            }
    
            return i;
        }
    }
    
    

    代码中要注意的是二分查找的代码,和我们平时写的有点不一样。需要仔细分析二分查找的几个要素(区间的开闭,终止条件,每次如何缩小范围),知乎上的这个帖子有的内容写的挺好的,可以参考借鉴一下。

    参考文献:《挑战程序设计竞赛-算法和数据结构》

  • 相关阅读:
    5 静态链接和动态链接
    4 程序编译与链接
    3.死锁
    2.调度算法
    1 select,poll和epoll
    python语言特性
    python动态规划
    python语言编程算法
    链表
    认识黑客常用的入侵方法
  • 原文地址:https://www.cnblogs.com/WanJiaJia/p/8033734.html
Copyright © 2011-2022 走看看