背包变异算法

时间:2012-04-30 15:57:08

标签: java algorithm knapsack-problem

作为家庭作业,我在java中有以下程序:

在书柜中,我们有一堆N本书,必须由K作家手工复制。 每本书都有Ui页面,其中Ai是书。

我们需要从堆栈中为每个作者提供连续的书籍,我们不能拆分书籍的页面。

制作一个程序,为作者提供书籍,但最大限度地减少作者将复制的最大页数。

作为输入,用户将给出一串数字,其中第一个数字是书籍数量N,第二个数字是作者数量K,其余数字是每本书籍的页数。

作为输出,程序将向用户输出作者将复制的最大页数。

示例:

输入:15 ​​6 30 40 10 40 50 20 30 40 10 70 10 50 30 50 10
输出:90

在这个例子中,第一个作者可以拿book1 = 30和book2 = 40但是不能拿book1 = 30,book3 = 10.换句话说,你只从书架顶部拿书而不混淆。< / p>

这是我的实施:

import java.util.*;

public class Library {

public static void main(String[] args) {
    Scanner input = new Scanner(System.in);

    // to work with 1.6 erase the second "Integer"
    //in 1.7 this works properly
    List<Integer> booksList = new LinkedList<Integer>();
    System.out.printf("Give: ");

    String answer = input.nextLine();
    String[] arr = answer.split(" ");

    for (String num : arr) {
        booksList.add(Integer.parseInt(num));
    }

    int books = booksList.remove(0);
    int writers = booksList.remove(0);

    while (booksList.size() > writers) {
        mergeMinimalPair(booksList);
    }

    System.out.println(getMax(booksList));
}

public static void mergeMinimalPair(List<Integer> books) {
    int index = 0;
    int minValue = books.get(0) + books.get(1);
    for (int i = 1; i < books.size() - 1; i++) {
        if ((books.get(i) + books.get(i + 1)) < minValue) {
            index = i;
            minValue = books.get(i) + books.get(i + 1);
        }
    }
    combine(books, index, index + 1);
}

public static void combine(List<Integer> books, int indexA, int indexB) {
    Integer a = books.get(indexA);
    Integer b = books.get(indexB);
    books.remove(indexB); 
    books.add(indexA, a + b);
    books.remove(indexB);
}

public static int getMax(List<Integer> books) {
    int max = books.get(0);
    for (int i = 1; i < books.size(); i++) {
        if (books.get(i) > max) {
            max = books.get(i);
        }
    }
    return max;
}
}

我所做的是每次将最小的一对书合并在一起,直到我的列表长度等于作者的数量但它不起作用,在示例中而不是90,它输出100。

我听说动态编程解决方案和残酷的解决方案可以解决背包问题,但在我的大学他们还没有教过我们关于动态规划的知识,所以要么教授对我们所知道的内容感到困惑,要么他希望我们找到一个残酷的解决方案。

我确信我的解决方案可行,但由于某种原因它只是没有,如果你能指出我在另一个解决方案中的提示或我误解的地方我会很高兴。

您可以指向DP解决方案或Brutal解决方案,但如果您指向DP解决方案,请注意我几乎不了解DP实施。

编辑:我已经看过一些类似背包的问题,​​但是我找不到一个有这种变化和我能理解的非DP解决方案

2 个答案:

答案 0 :(得分:2)

您可以对答案进行二元搜索。为作家选择一个最大值,比如说M,然后从左到右扫描书籍数组,为每个作者分配最多的书籍而不超过M。如果还有书籍,那么您必须增加M。如果您已成功分配了所有图书,请减少M

答案 1 :(得分:0)

这被称为partition problem的优化版本。它是NP-Hard。关于它,还有slick article。据我所知,有一个很好的启发式来近似它,但没有明确设计用于&#34;采取捷径的方法#34;在得到确切答案时。

我之前遇到过与此类似的问题,我的实际实现最终成为一种启发式方法(贪婪的方法很容易应用于任意数量的分区)然后进行几次迭代的优化(尝试交换/如果解决方案可能更好,那么在每次优化之后用支票移动一些权重(如果解决方案可能更好)(对于w写入者的p页面意味着每个作者的p / w页面是最佳的,尽管如果w不是& #39; t除p恰好p / w + 1是最佳的)。在您的情况下,因为您正在寻找一个精确的解决方案,您将需要一个最终强制执行的备份案例。

请注意,您只需要询问其中一个分区的最大总和是多少。这实际上是NP难的 - 知道更少的信息不仅仅是一个恒定的因子捷径。

如果我是你,我只是暴力强迫它。由于书籍数量少(少于十到二十),页面数量很大(100到1000),因此接近p / w的可能性很小,无法实现早期发布条件。另一方面,如果你需要处理任意数量的书籍,那么对于小尺寸和近似较大尺寸的书具有强力。