Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Подборка чисел в сумму 
:(
    Опции темы
1152010
  Дата 10.11.2010, 02:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Из базы выбираются записи, в одном из столбцов одни числа, средние между 10 и 100 обычно делимое на 5, но может и нет, кому как в голову стукнет.

Задача: Сказано собрать из этих чисел заданную сумму.

Никогда до этого с такой задачей не сталкивался, слабо представляю себе функцию.

 smile 
PM MAIL   Вверх
Akina
Дата 10.11.2010, 08:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Классическая задача о рюкзаке в простейшем варианте - одномерная и без весовых коэффициентов.


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

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


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Akina, при всём уважение, ничего не понял.

Пишу на ПХП потому, если соизволите дать пример, желательно либо образно , либо на доступном языке.
PM MAIL   Вверх
Akina
Дата 10.11.2010, 12:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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





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

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


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Прочёл артикль, покликал по сылкам, взорвал себе мозг. Ранец не плох, но там два ограничения, мне хватит одного.
В добавок не совсем могу осмыслить как это всё смешать с запросами к MYSQL. так как выдовать все числа это - громадные затраты памяти и нагрузка на сервер.  smile 
PM MAIL   Вверх
Akina
Дата 10.11.2010, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



ТАКИЕ задачи на SQL-сервере НЕ РЕШАЮТ!
SQL-сервер должен дать тебе сами числа. А вот реализация алгоритма подбора должна быть на клиенте. В твоём случае - на ПХП. Единственное удобство - ты можешь попросить от SQL-сервера дать тебе числа уже отсортированными, это немного упростит программирование алгоритма.


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

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


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Ну я не совсем сам SQL-иммел ввиду, вот так наваял пару дней назад, но чуствую что сильно не прав 
Код

if(!isset($_POST['sum']))
    {
    ?>
    <form action="test.php" method="post">
    <input type="text" name="sum">
    </form>
    <?
    }
else
    {
    $sum = $_POST['sum']; //nuzhnaja summa
    $ids = array(); //kuda zapisyvaem nuzhnye id 
    $idsindex = 0; //indeks dlja array
    $amounts = array(); //kuda zapisyvaem nuzhnye amount
    $amindex = 0; //indeks dlja array
    $col1 = true;

    while($col1)
        {
        $result = mysql_query("SELECT * FROM test WHERE amount<".($sum+1)." AND id NOT IN (".$ids.") AND status=1 ORDER BY amount DESC LIMIT 10");
        $sql++;
        $col2 = true;
        while($col2 AND $row = mysql_fetch_assoc($result))
            {
            if(($sum-$row['amount'])>=0)
                {
                $sql2++;
                $sum = $sum - $row['amount'];
                $ids[$idsindex] = $row['id'];
                $amounts[$amindex] = $row['amount'];
                $idsindex++;
                $amindex++;
                if($sum == 0)
                    {
                    $col2 = false;
                    $col1 = false;
                    }
                }
            else
                {
                $col2 = false;
                }
            }
        }

Как видно из кода, я просто разгружал SQL тем, что ограничивал выборку на 10 штук, ищя следующие по номиналу число
PM MAIL   Вверх
Akina
Дата 10.11.2010, 16:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Слушай, ты зачем SQL-сервер ставишь в неудобную позу? Получи одним запросом все свои числа, свали их в массив - и развлекайся на ПХП уже без него.


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

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


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Сейчас там для теста только 10.000 записей, а будет гораздо больше.... Не слишком ли много данных для передачи и для прогона потом массива?
PM MAIL   Вверх
Akina
Дата 10.11.2010, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



10тыс. чисел от 10 до 100? ну так передавай не по одному, а пару величина-количество...


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

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


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Akina, 
Код

GROUP BY
 ?

Ок, допустим сделаю, но проблема в том, что я не понимаю алгоритм перебора данных   smile  smile  smile 
PM MAIL   Вверх
Akina
Дата 11.11.2010, 08:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата(1152010 @  11.11.2010,  09:10 Найти цитируемый пост)
GROUP BY ?

Код

SELECT amount
     , count(amount) as cnt 
FROM test 
GROUP BY amount 
ORDER BY 1 DESC

Цитата(1152010 @  11.11.2010,  09:10 Найти цитируемый пост)
 я не понимаю алгоритм перебора данных

В таком случае используй метод ветвей и границ на сортированном по убыванию наборе.

Добавлено через 1 минуту и 43 секунды
Как я понимаю, у тебя задача - найти ЛЮБОЙ вариант, а не все возможные, верно?


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

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


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Akina, Не сочтите меня за лентея, но я не понимаю всех этих фраз, я сидел несколько часов пытаясь вникнуть в алгоритм с ранцем написанным на вике, в ваши посты. Вы пишите слишком много мне непонятных слов, я с этим всем не знаком. Я буду очень рад, если вы бы могли вами написаное, перевести в простой русский язык, указать на путь действий, в каком порядке, что перебирать.

Немного больше информации:
В таблице около 5 полей, но для данной задачи важны только 2: ИД записи, и сумма в строке, после подборки, мне нужно будет изменить статусы тех строк, которые вошли в сумму. Строки повторятся не могут. Я обратился за помощью потому, что те алгоритмы которые пытался написать я, они очень долго обрабатываются и с увелечением суммы и количества записей в базе и величины суммы просто вешаются.
PM MAIL   Вверх
Akina
Дата 11.11.2010, 16:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Гм... Ну ладно, всё одно делать пока нехрен... ща напишу поподробнее, если какая-нить клуша не припрётся с какой-нить ерундой.

Добавлено через 11 минут и 46 секунд
Значит, так. Будем реализовывать метод ветвей и границ в самом его колхозном варианте.

Мы уже получили перечень чисел, причём в порядке убывания (запрос - выше) и перенесли всё это в массив, не изменяя порядка. Теперь начнём набирать нужную сумму. Для того, чтобы хранить сведения, задействован или нет каждый контретный элемент, заведём в массиве ещё один столбик (есссно заранее) и для начала его обнулим. Заодно заведём переменную, в которой будем хранить номер последнего добавленного в набор элемента. И переменную под текущую сумму набора.

Берём первый элемент. Задействуем его (ставим в соотв. элемент единичку), добавляем его к сумме, фиксируем его номер. И далее:
Если текущая сумма меньше требуемой - пытаемся задействовать следующий за текущим элемент (пометка, прибавление, фиксация).
Если текущая сумма равна требуемой - мы счастливы, задача решена, берём элементы с единичками и выполняем апдейт (у нас же в массиве и колонка ИДов имеется, не так ли?).
А вот если сумма больше - шагаем назад. Проходим все подрад идущие единички, обнуляем их и пересчитываем сумму, затем проходим все подряд идущие нолики, пытаясь добраться до первой единички. 
Если добрались - обнуляем её (и пересчёт суммы), и задействуем следующий после неё элемент (единичка и пересчёт).
А вот если добрались до начала списка и не нашли единички - значит, сумму набрать не получится. О чём и сообщаем.

Возможен вариант, когда надо найти ближайший вариант. Ну тогда просто в доп. массиве храним наилучшее приближение суммы.


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

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


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


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

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



Поправка (вернее дополнение).
На шаге "если сумма больше - шагаем назад. Проходим все подрад идущие единички, обнуляем их и пересчитываем сумму, затем проходим все подряд идущие нолики, пытаясь добраться до первой единички" ПЕРВЫЙ раз обнуляем только свежедобавленную единичку, не производя возврата назад.

UPD. Нет, требуется поправка... ща.

Это сообщение отредактировал(а) Akina - 11.11.2010, 17:17


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

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


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Цитата(Akina @  11.11.2010,  16:41 Найти цитируемый пост)
Если текущая сумма меньше требуемой - пытаемся задействовать следующий за текущим элемент

А зачем? например сумма 480 первый самый большой на 450, а потом 50 варинтов пока не попадётся 20ка.

Но в принцепе я так и делал, перебирал всё по очереди, но вот только замечание от skyboy очень верно подметило слабую сторону перебора всех значений.
Цитата(skyboy @  7.11.2010,  02:25 Найти цитируемый пост)
в смысле, в первую очередь выбирать максимально допустимое из имеющихся чисел?
тогда на наборе 5,4,3,2 собери 10(5 + 4 + ... а дальше что? с другой стороны, 5 + 3 + 2 дают как раз 10).




Или я не правельно понял вами написаное?  smile 
PM MAIL   Вверх
baldina
Дата 11.11.2010, 18:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 4
Всего: 101



Цитата

замечание от skyboy очень верно подметило слабую сторону перебора всех значений

задача такова, что решается только перебором. другое дело, что проходя, скажем, от меньшего к большему, можно откинуть и не просматривать заведомо неподходящие варианты.
PM MAIL   Вверх
Akina
Дата 11.11.2010, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Ну в общем вот. Код написан на VBA. В MS Access 2003 на двухголовом пне 1.8 (всё равно используя только один проц) обрабатывает 10 тыщ записей за 8-10 секунд. Тыщу записей - за время менее дискретности системного таймера (55 мс).

Код

Private Const cnt As Integer = 10000 ' кол-во чисел
Private Const lim As Long = 32000 ' диапазон чисел от нуля и до
Private Const sum As Long = cnt * lim / 5 ' сумма, которую будем набирать

' Переменные
Dim x(0 To cnt, 0 To 1) As Integer ' массив значений и флагов включённости в сумму
Dim i As Integer
Dim j As Integer
Dim s As Long ' текущая сумма
Dim n As Integer ' текущий номер элемента

' процедура поиска (только констатирует факт, без вывода варианта)
Private Sub vg()

' Формируем массив и сортирим пузырём по убыванию
Randomize Timer
For i = 1 To cnt
    x(i, 1) = Rnd * lim 
Next
For i = 1 To cnt - 1
    For j = i + 1 To cnt
        If x(i, 1) < x(j, 1) Then
            x(i, 1) = x(i, 1) - x(j, 1)
            x(j, 1) = x(i, 1) + x(j, 1)
            x(i, 1) = x(j, 1) - x(i, 1)
        End If
    Next
Next

' фиксим время начала и понеслась
Debug.Print Time
n = 0
Do
    If n = cnt Then
        If GoBack Then
            Exit Do
        End If
    End If
    n = n + 1
    x(n, 0) = 1
    s = s + x(n, 1)
    If s = sum Then
        Debug.Print "Found."
        Exit Do
    End If
    If s > sum Then
        If n < cnt Then
            x(n, 0) = 0
            s = s - x(n, 1)
        Else
            If GoBack Then
                Exit Do
            End If
        End If
    End If
Loop
' фиксим время окончания
Debug.Print Time

End Sub

' функция возврата
Private Function GoBack() As Boolean
GoBack = False
While x(n, 0) = 1
    x(n, 0) = 0
    s = s - x(n, 1)
    n = n - 1
    If n = 0 Then
        Debug.Print "NOT Found."
        GoBack = True
        Exit Function
    End If
Wend
While x(n, 0) = 0
    n = n - 1
    If n = 0 Then
        Debug.Print "NOT Found."
        GoBack = True
        Exit Function
    End If
Wend
x(n, 0) = 0
s = s - x(n, 1)
End Function


Цитата(1152010 @  11.11.2010,  18:56 Найти цитируемый пост)
например сумма 480 первый самый большой на 450, а потом 50 варинтов пока не попадётся 20ка

нет проблем - оптимизируй, введи пропуск заведомо больших значений.


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

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


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Цитата(baldina @  11.11.2010,  18:34 Найти цитируемый пост)
задача такова, что решается только перебором. другое дело, что проходя, скажем, от меньшего к большему, можно откинуть и не просматривать заведомо неподходящие варианты. 

Это как? можно поподробней?
PM MAIL   Вверх
baldina
Дата 11.11.2010, 18:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 4
Всего: 101



Цитата

5,4,3,2 собери 10

5 < 10
5+4 < 10
5+4+3 > 10, возврат
5+3 < 10
5+3+2=10, решение найдено

2,3,4,5 собери 10
2 < 10
2+3 < 10
2+3+4 < 10
2+3+4+5 > 10, возврат
2+3+5=10, решение найдено

возврат означает, что мы отменяем последний добавленный элемент и пробуем следующий. если следующего нет, отменяем предпоследний ну и т.д.

Добавлено через 1 минуту и 13 секунд
а как именно это реализуется - см. пример Akina
PM MAIL   Вверх
1152010
Дата 11.11.2010, 18:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 6.11.2010

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



Цитата(baldina @  11.11.2010,  18:39 Найти цитируемый пост)
5 < 10
5+4 < 10
5+4+3 > 10, возврат
5+3 < 10

5+3+2=10, решение найдено

А по какому программно логическому ходу, ты отменил 4 а не 3? Вот иммено этот момент мне интересен, как избавится от слишком громадного перебора ненузжного? Может существуют вообще функции какие-то математические, с помощью которых это можно упростить?
PM MAIL   Вверх
baldina
Дата 11.11.2010, 18:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 4
Всего: 101



косяк. я сначала должен был 2 попробовать)))

Добавлено @ 18:53
Цитата

 как избавится от слишком громадного перебора ненузжного

этому и служит метод ветвей и границ

Добавлено @ 18:55
его мы и применяем. а уж как производить оценки, зависит от задачи
а просто перебор означал бы последовательную генерацию всех подмножеств и остановку, когда сумма станет 10

Добавлено @ 18:57
Цитата

5 < 10
5+4 < 10
5+4+3 > 10, возврат
5+3 < 10
5+3+2=10, решение найдено

5 < 10
5+4 < 10
5+4+3 > 10, возврат
5+4+2 > 10, возврат
5+3 < 10
5+3+2=10, решение найдено

Это сообщение отредактировал(а) baldina - 11.11.2010, 18:58
PM MAIL   Вверх
Akina
Дата 11.11.2010, 21:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата(baldina @  11.11.2010,  19:51 Найти цитируемый пост)
5 < 10
5+4 < 10
5+4+3 > 10, возврат
5+4+2 > 10, возврат
5+3 < 10
5+3+2=10, решение найдено

Приведённый мной код именно так и работает.


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

PM MAIL WWW ICQ Jabber   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

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


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

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


 




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


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

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