Я ищу разумный способ приблизиться к версии общей проблемы упаковки корзины. Учитывая количество пакетов (как я их называю) с определенной пропускной способностью и список предметов, занимающих определенное пространство, задача состоит в том, чтобы определить, могут ли все предметы помещаться в сумочки; и если да, то как. Сейчас у меня есть исчерпывающий DFS, но это требуется ... навсегда. Моя DFS является итеративной и требует копирования целых состояний на каждом шаге, что очень дорого. Вот мой код для конкретной проблемы с 4 мешками с 10 емкостью (действительно важными частями этого кода являются только метод pack() и класс State, если вы не хотите смотреть на все это):Алгоритм бин-упаковки, нуждающийся в ускорении
import java.util.ArrayList;
import java.util.Stack;
public class BagProblem {
int numBags;
int bagCapacity;
ArrayList<Item> items = new ArrayList<Item>();
public static void main(String[] args) {
BagProblem bp = new BagProblem(4, 10);
bp.pack();
}
public BagProblem(int numBags, int bagCapacity) {
this.numBags = numBags;
this.bagCapacity = bagCapacity;
items = new ArrayList<Item>();
items.add(new Item("item0", 6));
items.add(new Item("item1", 6));
items.add(new Item("item2", 6));
items.add(new Item("item5", 3));
items.add(new Item("item6", 3));
items.add(new Item("item7", 3));
items.add(new Item("item8", 2));
items.add(new Item("item9", 2));
items.add(new Item("item10", 2));
items.add(new Item("item11", 2));
items.add(new Item("item12", 2));
items.add(new Item("item13", 2));
items.add(new Item("item14", 1));
}
// find a valid way to pack and print the items in each Bag, or
// print failure
public void pack() {
Stack <State> s = new Stack<State>();
Bag[] currBags = new Bag[numBags];
for (int i = 0; i < numBags; i++) {
currBags[i] = new Bag(bagCapacity);
}
s.push(new State(currBags));
while(!s.isEmpty()) {
State currState = s.pop();
for (Item i : items) {
if (!currState.containsItem(i)) {
State newState = new State(currState.bags);
newState.numItems = currState.numItems;
if (newState.addItem(i)) {
s.push(newState);
if (newState.numItems == items.size()) {
System.out.println("success");
System.out.println(newState);
return;
}
}
}
}
}
System.out.println("failure");
}
private class State {
Bag[] bags;
int numItems;
public State(Bag[] currBags) {
bags = new Bag[numBags];
for (int i = 0; i < numBags; i++) {
bags[i] = new Bag(bagCapacity);
}
// figure out how to actually copy this
for (int j = 0; j < numBags; j++) {
Bag bagToCopy = currBags[j];
for (Item item : bagToCopy.contents) {
Item newItem = new Item(item.name, item.size);
bags[j].size = bagToCopy.size;
bags[j].contents.add(newItem);
}
}
}
public boolean addItem(Item i) {
for (Bag b : bags) {
if (b.addItem(i)) {
numItems++;
return true;
}
}
return false;
}
public boolean containsItem(Item i) {
for (Bag b : bags) {
for (Item item : b.contents) {
if (item.name.equals(i.name))
return true;
}
}
return false;
}
public String toString() {
String output = "";
for (Bag b : bags) {
for (Item j : b.contents) {
output += j.name + " ";
}
output += "\n";
}
return output;
}
}
private class Bag {
int capacity;
int size;
ArrayList<Item> contents;
public Bag(int capacity) {
this.capacity = capacity;
this.size = 0;
contents = new ArrayList<Item>();
}
public boolean addItem(Item i) {
if(size + i.size > capacity)
return false;
contents.add(i);
size += i.size;
return true;
}
public String toString() {
String output = "";
for (Item i : contents) {
output += i.name + " ";
}
return output + "\n";
}
}
private class Item {
String name;
int size;
public Item(String name, int size) {
this.name = name;
this.size = size;
}
public String toString() {
return name;
}
}
}
примерно через один миллион лет, это выплюнуть правильный ответ (вероятно, вы не хотите, чтобы на самом деле долго ждать, если вы попытаетесь запустить это):
success
item14 item7 item6 item5
item13 item12 item2
item11 item10 item1
item9 item8 item0
Каждая линия обозначает отдельную сумку. Как я могу ускорить это? Я знаю, что есть эвристика о попытке разместить самый большой элемент в первую очередь и т. Д., Но меня действительно интересует получение базовой DFS (или, может быть, я должен попробовать вернуться), чтобы иметь меньше накладных расходов; Я постараюсь поучаствовать позже.
Любая помощь была бы принята с благодарностью.
Здравствуйте и добро пожаловать в SO. Вы пробовали смотреть на Google и Википедию для алгоритмов? Например, first-fit-algoirthm может дать ответ очень быстро, но он не будет оптимальным. –
Проблема заключается в том, что в этой проблеме с упаковкой есть немного поворота. Мне нужно знать, может ли определенное количество мешков с определенной емкостью содержать набор предметов определенного размера; первоклассные и другие неоптимальные алгоритмы не смогут сказать. Я думаю, что DFS или backtracking должны быть единственным способом сделать это, но это просто так slooooow. Конечно, другое расположение предметов и сумок, которые сначала проверяются, может помочь, но сейчас я беспокоюсь, что я копирую больше информации на каждом шаге, чем мне действительно нужно, что убивает мое время выполнения. –
Что за твист? Вы точно описываете стандартную проблему упаковки бутылок. Эта проблема NP-hard, поэтому любое решение, которое гарантирует поиск оптимального ответа, будет медленным в больших случаях. Но если первая или другая эвристика упаковывают предметы в k мешков, вы знаете, что оптимальный ответ не более k, и вы можете доказать, что он не может быть k-1 или меньше (например, если общий размер элементов превышает (k-1) * bag_size), и в этом случае вы будете знать, что ответ оптимален. –