diff --git a/README.md b/README.md index c82d0ec..0bf4642 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ ## 1. Информация о студенте -**Номер группы**: 00-000 +**Номер группы**: 11-109 -**Фамилия и Имя**: Иванов Иван +**Фамилия и Имя**: Лямкин Сергей ## 2. Описание задания diff --git a/src/bits.cpp b/src/bits.cpp index 37cf7a0..9e68bbf 100644 --- a/src/bits.cpp +++ b/src/bits.cpp @@ -6,12 +6,12 @@ namespace assignment { bool is_bit_set(int mask, int pos) { assert(mask >= 0 && pos >= 0 && pos < 30); - return false; + return (mask & 1 << pos) != 0; } int set_bit(int mask, int pos) { assert(mask >= 0 && pos >= 0 && pos < 30); - return 0; + return mask | 1 << pos; } std::vector mask2indices(const std::vector& elems, int mask) { diff --git a/src/knapsack/backtracking.cpp b/src/knapsack/backtracking.cpp index d051dc2..9a81555 100644 --- a/src/knapsack/backtracking.cpp +++ b/src/knapsack/backtracking.cpp @@ -35,13 +35,28 @@ namespace assignment { // ... если текущая "польза" максимальна, обновляем наилучшую "пользу" if (profit > best_profit) { - // ... + best_profit = profit; + best_profit_mask = mask; } // рассматриваем следующий элемент index += 1; // ... рекурсивные вызовы со включением/исключением следующего элемента + const auto mask_profits = mask2elems(profits, mask); + int now_profit = 0; + for (int one_profit : mask_profits) { + now_profit += one_profit; + } + const auto masked_weights = mask2elems(weights, mask); + int now_weight = 0; + for (int one_weight : masked_weights) { + now_weight += one_weight; + } + solve(profits, weights, capacity, index, mask, now_weight, now_profit, best_profit, best_profit_mask); + solve(profits, weights, capacity, index, + set_bit(mask, index), now_weight + weights[index], + now_profit + profits[index], best_profit, best_profit_mask); } } // namespace assignment diff --git a/src/knapsack/bit_masking.cpp b/src/knapsack/bit_masking.cpp index 4160fef..fa68737 100644 --- a/src/knapsack/bit_masking.cpp +++ b/src/knapsack/bit_masking.cpp @@ -23,7 +23,9 @@ namespace assignment { int best_profit_mask = 0; // Tip: What if the weight is equal to the max weight? Can we stop the process? - + if (capacity == sum_helper(weights)) { + return mask2indices(profits, num_subsets - 1); + } // 0..00, 0..01, 0..10, 0..11, ..., 1..11 for (int mask = 0; mask < num_subsets; mask++) { // 2^N @@ -34,6 +36,9 @@ namespace assignment { const int curr_weight = sum_helper(masked_weights); // ... обработка случая превышения емкости рюкзака + if (curr_weight > capacity) { + continue; + } // массив из "пользы" рассматриваемых элементов const auto masked_profits = mask2elems(profits, mask); @@ -41,12 +46,16 @@ namespace assignment { // вычисление общей "пользы" рассматриваемых элементов const int curr_profit = sum_helper(masked_profits); + if (curr_profit > best_profit) { + best_profit = curr_profit; + best_profit_mask = mask; + } // ... обработка случая нахождения большего значения "пользы" } // ... возвращение итогового результата: используйте mask2indices; - return {}; + return mask2indices(profits, best_profit_mask); } } // namespace assignment \ No newline at end of file diff --git a/src/subset_sum/backtracking.cpp b/src/subset_sum/backtracking.cpp index c5c7469..4211686 100644 --- a/src/subset_sum/backtracking.cpp +++ b/src/subset_sum/backtracking.cpp @@ -32,13 +32,13 @@ namespace assignment { } // Ограничение 1: текущая сумма должна быть меньше целевой - if (true /* ... */) { + if (sum > target_sum) { // если превысили целевую сумму, то сделать ее меньше уже не получится (все элементы множества положительные) return; } // Ограничение 2: "остаточная сумма" + "текущая сумма" должны быть больше или равны "целевой сумме" - if (true /* ... */) { + if (residual + sum < target_sum) { // сумму невозможно будет набрать с оставшимися элементами множества return; } @@ -46,16 +46,25 @@ namespace assignment { // если найдено подмножество с целевой суммой, то сохраняем в результат это подмножество if (sum == target_sum) { // ... сохранение в результат + indices.push_back(mask2indices(set, mask)); // ... нужно ли в этой ветке рекурсии рассматривать следующие элементы? } // рассматриваем следующий элемент index += 1; - // обновляется несмотря на включение/исключение элемента => почему? + // обновляется несмотря на включение/исключение элемента => почему? (потому что мы не сможем + // добавить в множество элемент, который уже рассмотрели на прошлых шагах) residual -= set[index]; // рекурсивный вызов со включением/исключением элемента с текущим индексом ... + std::vector subset = mask2elems(set, mask); + search(set, index, mask, + std::accumulate(subset.begin(), subset.end(), 0), + residual, target_sum, indices); + search(set, index, set_bit(mask, index), + std::accumulate(subset.begin(),subset.end(), 0) + set[index], + residual, target_sum, indices); } } // namespace assignment \ No newline at end of file diff --git a/src/subset_sum/bit_masking.cpp b/src/subset_sum/bit_masking.cpp index 4deec18..cefb3e3 100644 --- a/src/subset_sum/bit_masking.cpp +++ b/src/subset_sum/bit_masking.cpp @@ -14,6 +14,21 @@ namespace assignment { const auto num_elems = static_cast(set.size()); // N const int num_subsets = 1 << num_elems; // 2^N + for (int mask = 0; mask < num_subsets; mask++) { + for (int pos = 0; pos < num_elems; pos++) { + std::vector subset = mask2indices(set, mask); + int summa = 0; + for (int index : subset) { + summa += set[index]; + } + if (summa > target_sum) { + break; + } + if (summa == target_sum) { + indices.push_back(subset); + } + } + } // 1. Внешний цикл: пробегаемся по всем битовым маскам от 0..00 до 1..11 // 2. Внутренний цикл: проверка разрядов битовой маски и генерация подмножества, ассоциирующегося с этой маской // 3. Подсчет суммы текущего подмножества, сохранение индексов подмножества с целевой суммой в результат diff --git a/src/subsets/backtracking.cpp b/src/subsets/backtracking.cpp index 256dd5b..1c08dac 100644 --- a/src/subsets/backtracking.cpp +++ b/src/subsets/backtracking.cpp @@ -27,7 +27,7 @@ namespace assignment { // Ограничение: рассмотрены все элементы множества if (index == static_cast(set.size()) - 1) { - + subsets.push_back(mask2indices(set, mask)); // ... сохранение полученного подмножества return; // возвращаемся по дереву рекурсии @@ -35,6 +35,8 @@ namespace assignment { index += 1; // рассматриваем следующий элемент + generate(set, index, mask, subsets); + generate(set, index, set_bit(mask, index), subsets); // здесь должны быть рекурсивные вызовы ... // включаем или не включаем элемент с текущим индексом в подмножество (используя битовую маску) } diff --git a/src/subsets/bit_masking.cpp b/src/subsets/bit_masking.cpp index feadd7e..5eb0969 100644 --- a/src/subsets/bit_masking.cpp +++ b/src/subsets/bit_masking.cpp @@ -15,6 +15,13 @@ namespace assignment { // выделяем память auto subsets = std::vector>(num_subsets); + for (int mask = 0; mask < num_subsets; mask++) { + for (int pos = 0; pos < num_elems; pos++) { + if (is_bit_set(mask, pos)) { + subsets[mask].push_back(pos); + } + } + } // 1. Внешний цикл: пробегаемся по всем битовым маскам от 0..00 до 1..11 // 2. Внутренний цикл: проверка разрядов битовой маски и генерация подмножества, ассоциирующегося с этой маской // Tips: для проверки разряда бита на 1 (единицу) используйте функцию is_bit_set