Change the algorithm for the neighbor set
This commit is contained in:
parent
6c7ba28320
commit
40f7dc5b49
2
sa.cpp
2
sa.cpp
@ -21,7 +21,7 @@ auto sa::solution::simulated_annealing(int capacity, const std::vector<long long
|
|||||||
|
|
||||||
int diff = neighbor.fitness - prev.fitness;
|
int diff = neighbor.fitness - prev.fitness;
|
||||||
if (diff <= 0 || std::exp(-diff / temp) > rand(eng)) {
|
if (diff <= 0 || std::exp(-diff / temp) > rand(eng)) {
|
||||||
prev.swap(neighbor);
|
swap(prev, neighbor);
|
||||||
}
|
}
|
||||||
|
|
||||||
temp *= alpha;
|
temp *= alpha;
|
||||||
|
|||||||
187
sa.hpp
187
sa.hpp
@ -1,54 +1,110 @@
|
|||||||
#ifndef SIMULATED_ANNEALING_HEADER_12647_H
|
#ifndef SIMULATED_ANNEALING_HEADER_12647_H
|
||||||
#define SIMULATED_ANNEALING_HEADER_12647_H
|
#define SIMULATED_ANNEALING_HEADER_12647_H
|
||||||
|
|
||||||
#define SIMULATED_ANNEALING_DISABLE_SHOWCRATES 1
|
#define SIMULATED_ANNEALING_DISABLE_SHOWCRATES 1
|
||||||
#define SIMULATED_ANNEALING_DISABLE_SHOWITRNUM 2
|
#define SIMULATED_ANNEALING_DISABLE_SHOWITRNUM 2
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <queue>
|
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <vector>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace sa {
|
namespace sa {
|
||||||
|
|
||||||
|
class box {
|
||||||
|
std::multiset<long long> 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<long long> &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 {
|
class solution {
|
||||||
std::vector<long long> items;
|
std::vector<box> boxes;
|
||||||
std::default_random_engine gen;
|
std::default_random_engine gen;
|
||||||
int capacity;
|
int capacity;
|
||||||
int fitness;
|
int fitness;
|
||||||
int iterations;
|
int iterations;
|
||||||
int iteration;
|
int iteration;
|
||||||
|
|
||||||
auto calculate_boxes()->int {
|
friend void swap(solution &one, solution &two) {
|
||||||
int count = 1;
|
using std::swap;
|
||||||
long long now = 0;
|
|
||||||
|
|
||||||
for (auto i : items) {
|
swap(one.boxes, two.boxes);
|
||||||
if (now + i > capacity) {
|
swap(one.gen, two.gen);
|
||||||
count++;
|
swap(one.capacity, two.capacity);
|
||||||
now = i;
|
swap(one.fitness, two.fitness);
|
||||||
continue;
|
swap(one.iterations, two.iterations);
|
||||||
}
|
swap(one.iteration, two.iteration);
|
||||||
now += i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_box(int box, std::queue<long long> &stored) {
|
|
||||||
std::cout << "Caixa " << box << ":";
|
|
||||||
while (!stored.empty()) {
|
|
||||||
std::cout << ' ' << stored.front();
|
|
||||||
stored.pop();
|
|
||||||
}
|
|
||||||
std::cout << '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
solution() = default;
|
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),
|
capacity(other.capacity), fitness(other.fitness),
|
||||||
iteration(itr) {}
|
iteration(itr) {}
|
||||||
|
|
||||||
@ -60,10 +116,8 @@ class solution {
|
|||||||
its.insert(i);
|
its.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->items.resize(items.size());
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
long long cap = capacity;
|
long long cap = capacity;
|
||||||
|
box tmp;
|
||||||
|
|
||||||
while (!its.empty()) {
|
while (!its.empty()) {
|
||||||
auto itr = its.upper_bound(cap);
|
auto itr = its.upper_bound(cap);
|
||||||
@ -71,40 +125,55 @@ class solution {
|
|||||||
cap = capacity;
|
cap = capacity;
|
||||||
cap -= *its.begin();
|
cap -= *its.begin();
|
||||||
itr = its.begin();
|
itr = its.begin();
|
||||||
|
this->boxes.emplace_back(tmp);
|
||||||
|
tmp.clear();
|
||||||
} else {
|
} else {
|
||||||
itr--;
|
itr--;
|
||||||
cap -= *itr;
|
cap -= *itr;
|
||||||
}
|
}
|
||||||
this->items[i] = *itr;
|
tmp.add_item(*itr);
|
||||||
its.erase(itr);
|
its.erase(itr);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fitness = calculate_boxes();
|
if (!tmp.empty()) {
|
||||||
|
this->boxes.emplace_back(tmp);
|
||||||
|
}
|
||||||
|
fitness = (int)this->boxes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setneighbor() { // Gera um vizinho da solução
|
void setneighbor() { // Gera um vizinho da solução
|
||||||
std::uniform_int_distribution<> dist(0, items.size() - 1);
|
std::uniform_int_distribution<> dist(0, (int)boxes.size() - 1);
|
||||||
int first = dist(gen);
|
|
||||||
int second = 0;
|
|
||||||
while ((second = dist(gen)) == first) {}
|
|
||||||
|
|
||||||
std::swap(items[first], items[second]);
|
int choice = dist(gen);
|
||||||
fitness = calculate_boxes();
|
std::vector<int> 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() {
|
void randomize() {
|
||||||
std::shuffle(items.begin(), items.end(), gen);
|
std::shuffle(boxes.begin(), boxes.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_sol(char flags = 0) const {
|
void print_sol(char flags = 0) const {
|
||||||
@ -115,23 +184,9 @@ class solution {
|
|||||||
std::cout << "Número de caixas: " << fitness << '\n';
|
std::cout << "Número de caixas: " << fitness << '\n';
|
||||||
|
|
||||||
if(!(flags & SIMULATED_ANNEALING_DISABLE_SHOWCRATES)){
|
if(!(flags & SIMULATED_ANNEALING_DISABLE_SHOWCRATES)){
|
||||||
int box_now = 1;
|
for (size_t i = 0; i < boxes.size(); i++) {
|
||||||
long long now = 0;
|
boxes[i].print((int)i + 1);
|
||||||
std::queue<long long> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
print_box(box_now, items_stored);
|
|
||||||
std::cout << '\n';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +196,7 @@ class solution {
|
|||||||
|
|
||||||
static auto simulated_annealing(int capacity, const std::vector<long long> &items,
|
static auto simulated_annealing(int capacity, const std::vector<long long> &items,
|
||||||
double alpha, double temp,
|
double alpha, double temp,
|
||||||
double temp_min)->solution;
|
double temp_min) -> solution;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sa
|
} // namespace sa
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user