From 40f7dc5b49d36bedf09fbcf9f885c345f7da2266 Mon Sep 17 00:00:00 2001 From: Segcolt <9hmbzr275@mozmail.com> Date: Sun, 13 Oct 2024 19:31:00 -0300 Subject: [PATCH] Change the algorithm for the neighbor set --- sa.cpp | 2 +- sa.hpp | 229 +++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 143 insertions(+), 88 deletions(-) diff --git a/sa.cpp b/sa.cpp index 14cfc81..3e5f762 100644 --- a/sa.cpp +++ b/sa.cpp @@ -21,7 +21,7 @@ auto sa::solution::simulated_annealing(int capacity, const std::vector rand(eng)) { - prev.swap(neighbor); + swap(prev, neighbor); } temp *= alpha; diff --git a/sa.hpp b/sa.hpp index 15a8933..b9f20e7 100644 --- a/sa.hpp +++ b/sa.hpp @@ -1,110 +1,179 @@ #ifndef SIMULATED_ANNEALING_HEADER_12647_H #define SIMULATED_ANNEALING_HEADER_12647_H + #define SIMULATED_ANNEALING_DISABLE_SHOWCRATES 1 #define SIMULATED_ANNEALING_DISABLE_SHOWITRNUM 2 #include #include -#include #include -#include #include +#include namespace sa { +class box { + std::multiset items; + long long fullness{}; + + friend void swap(box &one, box &two) { + using std::swap; + + swap(one.items, two.items); + swap(one.fullness, two.fullness); + } + + public: + + box() = default; + + box(const std::multiset &multiset, long long fullness): + items(multiset), fullness(fullness) {} + + void add_item(long long item) { + fullness += item; + items.insert(item); + } + + void clear() { + items.clear(); + fullness = 0; + } + + void pop() { + fullness -= *items.begin(); + items.erase(items.begin()); + } + + auto swap10(box &other, int capacity) -> bool { + if (*items.begin() + other.fullness > capacity) { + return false; + } + other.add_item(*items.begin()); + pop(); return true; } + + auto swap11(box &other, int capacity) -> bool { + long long choice1 = *items.begin(); + long long choice2 = *other.items.begin(); + + if (choice1 + other.fullness - choice2 > capacity || + choice2 + fullness - choice1 > capacity) { + return false; + } + + pop(); + other.pop(); + add_item(choice2); + other.add_item(choice1); + + return true; + } + + void print(int ind) const { + std::cout << "Caixa " << ind << ":"; + for (auto item : items) { + std::cout << ' ' << item; + } + std::cout << '\n'; + } + + [[nodiscard]] auto empty() const -> bool { + return fullness == 0; + } +}; + class solution { - std::vector items; + std::vector boxes; std::default_random_engine gen; int capacity; int fitness; int iterations; int iteration; - auto calculate_boxes()->int { - int count = 1; - long long now = 0; + friend void swap(solution &one, solution &two) { + using std::swap; - for (auto i : items) { - if (now + i > capacity) { - count++; - now = i; - continue; - } - now += i; - } - - return count; - } - - static void print_box(int box, std::queue &stored) { - std::cout << "Caixa " << box << ":"; - while (!stored.empty()) { - std::cout << ' ' << stored.front(); - stored.pop(); - } - std::cout << '\n'; + swap(one.boxes, two.boxes); + swap(one.gen, two.gen); + swap(one.capacity, two.capacity); + swap(one.fitness, two.fitness); + swap(one.iterations, two.iterations); + swap(one.iteration, two.iteration); } public: solution() = default; - solution(const solution &other, int itr): items(other.items), gen(other.gen), + solution(const solution &other, int itr): boxes(other.boxes), gen(other.gen), capacity(other.capacity), fitness(other.fitness), iteration(itr) {} solution(const std::vector &items, int capacity): // Gera a solução inicial gen(std::random_device()()), capacity(capacity), iteration(0) { - std::multiset its; - for (auto i : items) { - its.insert(i); - } - - this->items.resize(items.size()); - size_t i = 0; - - long long cap = capacity; - - while (!its.empty()) { - auto itr = its.upper_bound(cap); - if (itr == its.begin()) { - cap = capacity; - cap -= *its.begin(); - itr = its.begin(); - } else { - itr--; - cap -= *itr; - } - this->items[i] = *itr; - its.erase(itr); - i++; - } - - fitness = calculate_boxes(); + std::multiset its; + for (auto i : items) { + its.insert(i); } - void setneighbor() { // Gera um vizinho da solução - std::uniform_int_distribution<> dist(0, items.size() - 1); - int first = dist(gen); - int second = 0; - while ((second = dist(gen)) == first) {} + long long cap = capacity; + box tmp; - std::swap(items[first], items[second]); - fitness = calculate_boxes(); + while (!its.empty()) { + auto itr = its.upper_bound(cap); + if (itr == its.begin()) { + cap = capacity; + cap -= *its.begin(); + itr = its.begin(); + this->boxes.emplace_back(tmp); + tmp.clear(); + } else { + itr--; + cap -= *itr; + } + tmp.add_item(*itr); + its.erase(itr); + } + + if (!tmp.empty()) { + this->boxes.emplace_back(tmp); + } + fitness = (int)this->boxes.size(); + } + + void setneighbor() { // Gera um vizinho da solução + std::uniform_int_distribution<> dist(0, (int)boxes.size() - 1); + + int choice = dist(gen); + std::vector sequence(boxes.size() - 1); + for (size_t i = 0; i < choice; i++) { + sequence[i] = i; + } + for (size_t i = choice + 1; i < boxes.size(); i++) { + sequence[i - 1] = i; + } + + shuffle(sequence.begin(), sequence.end(), gen); + + for (auto ind : sequence) { + if (boxes[choice].swap10(boxes[ind], capacity)) { + if (boxes[choice].empty()) { + boxes.erase(boxes.begin() + choice); + } + fitness = (int)boxes.size(); + return; + } + } + + for (auto ind : sequence) { + if (boxes[choice].swap11(boxes[ind], capacity)) { + return; + } + } } void randomize() { - std::shuffle(items.begin(), items.end(), gen); - - fitness = calculate_boxes(); - } - - void swap(solution &other) { - std::swap(fitness, other.fitness); - std::swap(items, other.items); - std::swap(capacity, other.capacity); - std::swap(gen, other.gen); - std::swap(iteration, other.iteration); + std::shuffle(boxes.begin(), boxes.end(), gen); } void print_sol(char flags = 0) const { @@ -115,23 +184,9 @@ class solution { std::cout << "Número de caixas: " << fitness << '\n'; if(!(flags & SIMULATED_ANNEALING_DISABLE_SHOWCRATES)){ - int box_now = 1; - long long now = 0; - std::queue items_stored; - - for (auto i : items) { - if (now + i > capacity) { - print_box(box_now, items_stored); - box_now++; - now = i; - } else { - now += i; - } - items_stored.push(i); + for (size_t i = 0; i < boxes.size(); i++) { + boxes[i].print((int)i + 1); } - - print_box(box_now, items_stored); - std::cout << '\n'; } } @@ -141,7 +196,7 @@ class solution { static auto simulated_annealing(int capacity, const std::vector &items, double alpha, double temp, - double temp_min)->solution; + double temp_min) -> solution; }; } // namespace sa