Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ int main() {

return 0;
}
#
6 changes: 3 additions & 3 deletions src/bits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
namespace assignment {

bool is_bit_set(int mask, int pos) {
assert(mask >= 0 && pos >= 0 && pos < 30);
return false;
assert(mask >= 0 && pos >= 0 && pos < 30); // pos < макс. кол-ва бит в маске
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<int> mask2indices(const std::vector<int>& elems, int mask) {
Expand Down
7 changes: 5 additions & 2 deletions src/knapsack/backtracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ namespace assignment {

// ... если текущая "польза" максимальна, обновляем наилучшую "пользу"
if (profit > best_profit) {
// ...
best_profit_mask = mask;
best_profit = profit;
}

// рассматриваем следующий элемент
index += 1;
solve(profits,weights,capacity,index, set_bit(mask,index),weight + weights[index],profit + profits[index],best_profit,best_profit_mask);
solve(profits,weights,capacity,index,mask,weight,profit,best_profit,best_profit_mask );

// ... рекурсивные вызовы со включением/исключением следующего элемента
}

} // namespace assignment
} // namespace assignment
9 changes: 8 additions & 1 deletion src/knapsack/bit_masking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ namespace assignment {
const int curr_weight = sum_helper(masked_weights);

// ... обработка случая превышения емкости рюкзака
if (curr_weight > capacity){
continue;
}

// массив из "пользы" рассматриваемых элементов
const auto masked_profits = mask2elems(profits, mask);
Expand All @@ -42,11 +45,15 @@ 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
8 changes: 6 additions & 2 deletions src/subset_sum/backtracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ namespace assignment {
}

// Ограничение 1: текущая сумма должна быть меньше целевой
if (true /* ... */) {
if (sum > target_sum) {
// если превысили целевую сумму, то сделать ее меньше уже не получится (все элементы множества положительные)
return;
}

// Ограничение 2: "остаточная сумма" + "текущая сумма" должны быть больше или равны "целевой сумме"
if (true /* ... */) {
if (sum + residual < target_sum) {
// сумму невозможно будет набрать с оставшимися элементами множества
return;
}
Expand All @@ -47,6 +47,8 @@ namespace assignment {
if (sum == target_sum) {
// ... сохранение в результат
// ... нужно ли в этой ветке рекурсии рассматривать следующие элементы?
indices.push_back(mask2indices(set, mask));
return;
}

// рассматриваем следующий элемент
Expand All @@ -56,6 +58,8 @@ namespace assignment {
residual -= set[index];

// рекурсивный вызов со включением/исключением элемента с текущим индексом ...
search(set, index, set_bit(mask, index), sum + set[index], residual, target_sum, indices);
search(set, index, mask, sum, residual, target_sum, indices);
}

} // namespace assignment
49 changes: 37 additions & 12 deletions src/subset_sum/bit_masking.cpp
Original file line number Diff line number Diff line change
@@ -1,25 +1,50 @@
#include "assignment/subset_sum/bit_masking.hpp"
#include "assignment/knapsack/backtracking.hpp"

#include <cassert> // assert

#include "assignment/bits.hpp" // is_bit_set, mask2indices
#include "assignment/bits.hpp"

namespace assignment {

std::vector<std::vector<int>> SubsetSumBitMasking::search(const std::vector<int>& set, int target_sum) const {
assert(target_sum > 0 && set.size() <= 16);
std::vector<int> KnapsackBacktracking::solve(const Profits& profits, const Weights& weights, int capacity) const {
assert(profits.size() == weights.size() && capacity > 0);

std::vector<std::vector<int>> indices;
// результат: наибольшая "польза"
int best_profit = 0;
int best_profit_mask = 0;

const auto num_elems = static_cast<int>(set.size()); // N
const int num_subsets = 1 << num_elems; // 2^N
// вызов вспомогательного метода: обратите внимание на входные аргументы
// и на то, как они передаются (по значению или ссылке, почему так?)
solve(profits, weights, capacity, -1, 0, 0, 0, best_profit, best_profit_mask);

// 1. Внешний цикл: пробегаемся по всем битовым маскам от 0..00 до 1..11
// 2. Внутренний цикл: проверка разрядов битовой маски и генерация подмножества, ассоциирующегося с этой маской
// 3. Подсчет суммы текущего подмножества, сохранение индексов подмножества с целевой суммой в результат
// Tips: можно пропустить итерацию, если сумма текущего подмножества стала больше целевой суммы
return mask2indices(profits, best_profit_mask);
}

void KnapsackBacktracking::solve(const Profits& profits, const Weights& weights, int capacity, int index, int mask,
int weight, int profit, int& best_profit, int& best_profit_mask) const {

// Ограничение 0: выход за пределы
if (index == static_cast<int>(profits.size())) {
return;
}

// Ограничение 1: превышение лимита емкости рюкзака
if (weight > capacity) {
return;
}

// ... если текущая "польза" максимальна, обновляем наилучшую "пользу"
if (profit > best_profit) {
best_profit_mask = mask;
best_profit = profit;
}

// рассматриваем следующий элемент
index += 1;
solve(profits,weights,capacity,index, set_bit(mask,index),weight + weights[index],profit + profits[index],best_profit,best_profit_mask);
solve(profits,weights,capacity,index,mask,weight,profit,best_profit,best_profit_mask );

return indices;
// ... рекурсивные вызовы со включением/исключением следующего элемента
}

} // namespace assignment
39 changes: 12 additions & 27 deletions src/subsets/backtracking.cpp
Original file line number Diff line number Diff line change
@@ -1,42 +1,27 @@
#include "assignment/subsets/backtracking.hpp"
#include "assignment/subsets/bit_masking.hpp"

#include <cassert> // assert

#include "assignment/bits.hpp" // is_bit_set, set_bit, mask2indices
#include "assignment/bits.hpp" // is_bit_set

namespace assignment {

std::vector<std::vector<int>> SubsetsBacktracking::generate(const std::vector<int>& set) const {
std::vector<std::vector<int>> SubsetsBitMasking::generate(const std::vector<int>& set) const {
assert(set.size() <= 16);

const auto num_elems = static_cast<int>(set.size()); // N
const int num_subsets = 1 << num_elems; // 2^N

auto subsets = std::vector<std::vector<int>>();
subsets.reserve(num_subsets);

// вызов вспомогательной функции: обратите внимание на начальное значение индекса и маски
generate(set, -1, 0, subsets);

return subsets;
}

void SubsetsBacktracking::generate(const std::vector<int>& set, int index, int mask,
std::vector<std::vector<int>>& subsets) const {
assert(mask >= 0 && index >= -1);

// Ограничение: рассмотрены все элементы множества
if (index == static_cast<int>(set.size()) - 1) {

// ... сохранение полученного подмножества

return; // возвращаемся по дереву рекурсии
auto subsets = std::vector<std::vector<int>>(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);
}
}
}

index += 1; // рассматриваем следующий элемент

// здесь должны быть рекурсивные вызовы ...
// включаем или не включаем элемент с текущим индексом в подмножество (используя битовую маску)
return subsets;
}

} // namespace assignment