Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Оптимизация, получение суммы используя, минимальное количество элементов 
V
    Опции темы
Stolzen
Дата 10.8.2012, 11:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1041
Регистрация: 17.10.2005

Репутация: нет
Всего: 48



Всем доброго времени суток!

Задача следующая: 
Есть множество P каждый элемент которого имеет некоторую цену pi; и есть заданная цена W. 
Необходимо выбрать элементы из P так, чтобы количество элементов было минимальным, а сумма цен элементов была больше или равна W. Если вариантов несколько, выбрать тот, который ближе к W.

Например, 
элементы [100, 20, 30, 50], цена 100, нужно выбрать [100]
элементы [100, 30, 20, 50, 10], цена 80, нужно выбрать [50, 30]
элементы [100, 30, 20, 50, 10], цена 85, нужно выбрать [50, 30, 10]

Теорию оптимизации совсем не помню, поэтому буду признателен любой наводке.

Добавлено через 2 минуты и 18 секунд
Да, кстати, числа могут быть довольно большими (в пределах long)


--------------------
datatalks.ru - анализ данных, статистика, машинное обучение
PM MAIL WWW   Вверх
Stolzen
Дата 10.8.2012, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1041
Регистрация: 17.10.2005

Репутация: нет
Всего: 48



Вот что придумалось

поиск (P, W, результат)
  •  Если P пустой и W > 0, возвращаем пустой список
  •  Если P пустой и W < 0, возвращаем результат
  •  P не пустой. Есть два варианта - поместить первый элемент из P в результат или не поместить
  •  помещаем p0 в результат: with <- поиск(tail(P), W - head(P), head(P) ++ результат)
  •  не помещаем p0 в результат: without <- поиск(tail(P), W, результат)
  •  если сумма в with больше W, а сумма в without меньше, возвращем with
  •  если сумма в with меньше W, а сумма в without больше, возвращем without 
  •  если сумма в with меньше W, и сумма в without меньше, возвращем пустой список
  •  если сумма в with ближе к W, возвращаем with, иначе without
  •  если сумма одинаковая, а количество элементов в with меньше, возвращаем with, иначе without
Перед этим еще можно сразу же выкинуть все элементы из P, которые больше W и заодно проверить, есть ли в P такой pi что pi == W
Чем-то напомнинает рюкзак. Что скажете?

Это сообщение отредактировал(а) Stolzen - 10.8.2012, 15:20


--------------------
datatalks.ru - анализ данных, статистика, машинное обучение
PM MAIL WWW   Вверх
Akina
Дата 10.8.2012, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 20
Всего: 454



Цитата(Stolzen @  10.8.2012,  12:19 Найти цитируемый пост)
Необходимо выбрать элементы из P так, чтобы количество элементов было минимальным, а сумма цен элементов была больше или равна W. Если вариантов несколько, выбрать тот, который ближе к W.

Вывод из формулировки - количество приоритетнее близости суммы. Следовательно, во 2 и 3 вариантах следует выбрать то же решение, что и в первом варианте - именно это решение даёт минимальное количество элементов.

Цитата(Stolzen @  10.8.2012,  13:39 Найти цитируемый пост)
Что скажете?

Прежде чем формулировать задачу остальным, следует её до конца осмыслить для себя.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Stolzen
Дата 10.8.2012, 15:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1041
Регистрация: 17.10.2005

Репутация: нет
Всего: 48



Да, не совсем верно сформулировал, близость к сумме конечно приоритетнее, чем количество элементов. 


--------------------
datatalks.ru - анализ данных, статистика, машинное обучение
PM MAIL WWW   Вверх
korian
Дата 12.8.2012, 14:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 1
Всего: 17



Думаю так должно работать быстрее:
Код

public class Sum {
    //основная точка входа
    public static Result find(final List<Integer> elements, final int minSum) {
        if (elements.isEmpty()) //если элементов нету
            return null; //нету решений
        Collections.sort(elements); //сортируем элементы по возрастанию
        return findInSortedArray(elements, minSum); //основная функциональность
    }

    //требование - элементы отсортированы и количество элементов больше нуля. minSum - это W в вашем описании
    public static Result findInSortedArray(final List<Integer> elements, final int minSum) {
        int index = Collections.binarySearch(elements, minSum); //поиск элемента
        if (index >= 0) //если нашли
            return new Result(elements.get(index)); //возвращаем его как результат

        int upperBoundIndex = -index - 1; //элемент не найден, здесь индекс элемента, который больше чем minSum (может указывать за пределы множества, если большего элемента нету)
        if (upperBoundIndex == 0) //элементов меньше чем minSum нету
            return new Result(elements.get(upperBoundIndex)); //возвращаем первый, больший чем minSum, элемент

        List<Integer> leftElements = elements.subList(0, upperBoundIndex); //создается подмножество элементов, которое содержит только элементы, которые меньше minSum
        Result leftResult = findBestSum(leftElements, minSum); //поиск решения для подмножества
        Result rightResult = null;
        if (upperBoundIndex != elements.size()) //существует элемент, который больше minSum
            rightResult = new Result(elements.get(upperBoundIndex)); //создаем решение на основе большего элемента

        return Result.getBetter(rightResult, leftResult); //выбираем лучший вариант
    }

    //требование - элементы отсортированы, количество элементов больше нуля и среди элементов, нету элементов больше minSum
    public static Result findBestSum(List<Integer> elements, final int minSum) {
        Result result = null;

        while (true) {
            int lastIndex = elements.size() - 1;
            int lastValue = elements.get(lastIndex);
            elements = elements.subList(0, lastIndex); //создается подмножество элементов, которое не содержит последний элемент
            if (elements.isEmpty()) //если подмножество пусто
                break; //выходим

            Result subResult = findInSortedArray(elements, minSum - lastValue); //поиск решения для подмножества без последнего элемента, и W = minSum - <значение последнего элемента>
            if (subResult == null) //решенией нет
                break; //выходим (их уже и не будет, т.к. массив отсортирован)

            Result newResult = new Result(subResult, lastValue); //Формируем решение на основе решения для подмножества. Result = {<Result для подмножества>, lastValue}. lastValue - удаленные элемент из подмножества

            result = Result.getBetter(result, newResult); //выбираем лучшее решение между текущим и вновь посчитанным.
        }

        return result;
    }
}

Код

public class Result {
    private final List<Integer> elements;
    private final int sum;
    
    public Result(int oneElement) {
        this.elements = Collections.singletonList(oneElement);
        this.sum = oneElement;
    }

    public Result(Result subResult, int newValue) {
        this.elements = new ArrayList<>(subResult.elements);
        this.elements.add(newValue);
        this.sum = subResult.getSum() + newValue;
    }

    public int get(int index) {
        return elements.get(index);
    }
    public int size() {
        return elements.size();
    }
    public int getSum() {
        return sum;
    }

    public static Result getBetter(Result left, Result right) {
        if (right == null)
            return left;
        if (left == null)
            return right;
        if (left.getSum() < right.getSum())
            return left;
        if (left.getSum() > right.getSum())
            return right;
        if (left.size() > right.size())
            return right;
        return left;
    }
}


Это сообщение отредактировал(а) korian - 13.8.2012, 17:35
PM   Вверх
Stolzen
Дата 13.8.2012, 10:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1041
Регистрация: 17.10.2005

Репутация: нет
Всего: 48



korian, спасибо. А можно на словах описать, что тут происходит? 
У меня вот такая реализация для алгоритма выше получилась.


--------------------
datatalks.ru - анализ данных, статистика, машинное обучение
PM MAIL WWW   Вверх
Akina
Дата 13.8.2012, 12:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 20
Всего: 454



Цитата(Stolzen @  10.8.2012,  16:03 Найти цитируемый пост)
близость к сумме конечно приоритетнее, чем количество элементов. 

Всё равно не до конца понятно. Как они соотносятся? если нужна сумма 98, она не набирается, а набирается 99 из 11 элементов или 100 одним элементом - какой вариант выбрать?
Где математическое определение критерия оптимальности?


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Stolzen
Дата 13.8.2012, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1041
Регистрация: 17.10.2005

Репутация: нет
Всего: 48



Цитата(Akina @  13.8.2012,  13:30 Найти цитируемый пост)
Где математическое определение критерия оптимальности? 

У меня нет такого, извините.

Цитата(Akina @  13.8.2012,  13:30 Найти цитируемый пост)
если нужна сумма 98, она не набирается, а набирается 99 из 11 элементов или 100 одним элементом - какой вариант выбрать?

Склоняюсь к 99.

Меня, по правде, больше интересовали подходы к решению подобных задач. Спасибо.


--------------------
datatalks.ru - анализ данных, статистика, машинное обучение
PM MAIL WWW   Вверх
korian
Дата 13.8.2012, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 1
Всего: 17



Цитата(Stolzen @  13.8.2012,  09:28 Найти цитируемый пост)
 А можно на словах описать, что тут происходит? 

Я добавил комментарии.

Цитата(Stolzen @  13.8.2012,  09:28 Найти цитируемый пост)
У меня вот такая реализация для алгоритма выше получилась. 

Мне тяжело читать функциональные языки %)
Можете проверить ваш алгоритм на таких данных (я их использовал для своих тестов и это вроде как основные моменты, которые надо проверить):
Код

P = {50, 20, 30}
W = 50
Result = {50}

P = {10, 20}
W = 5
Result = {10}

P = {5, 10, 30}
W = 20
Result = {30}

P = {40, 50, 80}
W = 65
Result = {80}

P = {10}
W = 80
Result = null

P = {10, 20}
W = 40
Result = null

P = {10, 15, 20}
W = 30
Result = {10, 20}

P = {10, 20, 30, 41}
W = 50
Result = {20, 30}

P = {1, 2, 23, 30, 50}
W = 53
Result = {23, 30}


Если все это у вас работает, то единственный плюс в моем алгоритме - из-за того, что элементы отсортированы, нужно делать меньший перебор.


Это сообщение отредактировал(а) korian - 13.8.2012, 17:11
PM   Вверх
Akina
Дата 13.8.2012, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 20
Всего: 454



Цитата(Stolzen @  13.8.2012,  14:14 Найти цитируемый пост)
Меня, по правде, больше интересовали подходы к решению подобных задач. 

Ну здесь Вы собсно имеете в чистом виде задачу об одномерном раскрое. И решаете её соответственно. Либо какой-то точный переборный метод, скажем метод ветвей и границ, либо (если устраивает решение, близкое к оптимуму, а необязательно оптимум) генетика.

Цитата(Stolzen @  13.8.2012,  14:14 Найти цитируемый пост)
У меня нет такого, извините.

А вот это очень плохо. Вы обязаны иметь... ммм... ну, скажем, функцию, в которую Вы передаёте два решения, а она возвращает ответ, какое из них лучше. Иначе решать задачу не получится. Ощущения класса "склоняюсь к" не программируются.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Stolzen
Дата 14.8.2012, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1041
Регистрация: 17.10.2005

Репутация: нет
Всего: 48



Цитата(Akina @  13.8.2012,  21:59 Найти цитируемый пост)
Ну здесь Вы собсно имеете в чистом виде задачу об одномерном раскрое. И решаете её соответственно. Либо какой-то точный переборный метод, скажем метод ветвей и границ, либо (если устраивает решение, близкое к оптимуму, а необязательно оптимум) генетика.

Спасибо, именно это мне больше всего хотелось услышать. Почитаю про одномерный раскрой и метод ветвей и границ. 

Цитата(Akina @  13.8.2012,  21:59 Найти цитируемый пост)
А вот это очень плохо. Вы обязаны иметь... ммм... ну, скажем, функцию, в которую Вы передаёте два решения, а она возвращает ответ, какое из них лучше. Иначе решать задачу не получится. Ощущения класса "склоняюсь к" не программируются. 

Дело в том, что мы пока в команде сами не знаем, какие именно критерии выбора решения лучше использовать, поэтому перебираем разные варианты и смотрим, какой из них лучше ведет себя для тестового набора данных. Ну и в данном случае ведь выбор ответа - это дело одной-двух проверок, поэтому можно сначала проверить ощущения типа "склоняюсь к", а потом другие  smile 

Цитата(korian @  13.8.2012,  18:11 Найти цитируемый пост)
Можете проверить ваш алгоритм на таких данных (я их использовал для своих тестов и это вроде как основные моменты, которые надо проверить):

Спасибо, нашел пару опечаток и неточностей в коде. (Вот новая версия.)

Цитата(korian @  13.8.2012,  18:11 Найти цитируемый пост)
Я добавил комментарии.

Да, теперь немного понятнее. Получается, примерно такая же идея, как в посте 2, только алгоритм реализован эффективнее? У этого алгоритма есть какое-нибудь название?




--------------------
datatalks.ru - анализ данных, статистика, машинное обучение
PM MAIL WWW   Вверх
Akina
Дата 14.8.2012, 12:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 20
Всего: 454



Цитата(Stolzen @  14.8.2012,  12:28 Найти цитируемый пост)
Почитаю про одномерный раскрой 

Заодно почитай и задачу о рюкзаке (вариация - об одномерном рюкзаке). Она отличается от раскроя тем, что в ней есть относительные веса/стоимости, о чём обычно забывают, благополучно путая меж собой эти задачи.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
korian
Дата 14.8.2012, 17:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 651
Регистрация: 8.3.2008
Где: Украина, Харьков

Репутация: 1
Всего: 17



Цитата(Stolzen @  14.8.2012,  10:28 Найти цитируемый пост)
Да, теперь немного понятнее. Получается, примерно такая же идея, как в посте 2, только алгоритм реализован эффективнее?

В общем да. Эффективнее тем, что я на каждом шаге уменьшаю размер множества, если это возможно. Т.е. рассматриваю подмножество элементов, в котором только элементы, которые меньше W, плюс один наименьший элемент, который больше W. Ну и учитывая, что множество отсортированное, это стоит мне всего log(n) времени.
Плюс если я правильно понимаю, моему алгоритму надо меньше времени для определения, что сумма множества меньше W.

Цитата(Stolzen @  14.8.2012,  10:28 Найти цитируемый пост)
У этого алгоритма есть какое-нибудь название?

Без понятия, особо этим не интересовался. Написан за субботу от нечего делать.


Это сообщение отредактировал(а) korian - 14.8.2012, 17:03
PM   Вверх
Stolzen
Дата 14.8.2012, 17:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1041
Регистрация: 17.10.2005

Репутация: нет
Всего: 48



korianAkina, спасибо вам за отклик, на пока тему можно считать закрытой. 


--------------------
datatalks.ru - анализ данных, статистика, машинное обучение
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Алгоритмы | Следующая тема »


 




[ Время генерации скрипта: 0.1363 ]   [ Использовано запросов: 20 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.