3D-Projects/OfficeShelf/zuschnitt_cpp/zuscnitt/main.cpp

287 lines
7.3 KiB
C++

#include <cassert>
#include <ctime>
#include <iostream>
#include <memory>
#include <vector>
bool intvectcontains(const std::vector<int> &heystack, int needle) {
for (auto i: heystack) {
if (i == needle) return true;
}
return false;
}
class Cut {
public:
Cut(int l) {
this->Length = l;
}
int length() const {
return this->Length;
}
private:
Cut(Cut &); // deny copying
int Length = 0;
};
class CutableRod {
public:
CutableRod() {
this->Length = 6000;
this->CutThickness = 9;
this->Remainder = this->Length;
}
CutableRod(CutableRod &other) {
this->Length = other.Length;
this->CutThickness = other.CutThickness;
this->Remainder = other.Remainder;
for (auto c : other.Cuts) {
this->Cuts.push_back(c);
}
}
void addCut(std::shared_ptr<const Cut> cut) {
assert(this->canAddCut(cut));
this->Cuts.push_back(cut);
this->Remainder -= cut->length();
this->Remainder -= this->CutThickness;
}
bool canAddCut(std::shared_ptr<const Cut> cut) {
return this->Remainder >= cut->length();
}
std::vector<std::shared_ptr<const Cut>> cuts() {
return this->Cuts;
}
int remainder() {
return this->Remainder;
}
int variety(void) {
std::vector<int> lengths;
for (auto cut : this->Cuts) {
if (!intvectcontains(lengths, cut->length()))
lengths.push_back(cut->length());
}
return lengths.size();
}
private:
int Length = 0;
int CutThickness = 0;
int Remainder = 0;
std::vector<std::shared_ptr<const Cut>> Cuts;
};
class CutSolution {
public:
CutSolution() {
}
CutSolution(CutSolution &other) {
for (auto r_other: other.Rods) {
auto r_copy = std::make_shared<CutableRod>(*r_other);
this->Rods.push_back(r_copy);
}
}
void addCut(std::shared_ptr<const Cut> cut) {
// add rod if empty
if (this->Rods.empty()) {
auto new_rod = std::make_shared<CutableRod>();
this->Rods.push_back(new_rod);
}
// add rod if cannot add cut
if (!this->Rods.back()->canAddCut(cut)) {
auto new_rod = std::make_shared<CutableRod>();
this->Rods.push_back(new_rod);
}
// add cut to last rod
this->Rods.back()->addCut(cut);
}
bool isBetterThan(const CutSolution &other) {
// compare rod amount
int my_r = this->rods();
int other_r = other.rods();
if (my_r != other_r) {
return my_r < other_r;
// compare remainder amount
} else {
int my_r = this->remainder();
int other_r = other.remainder();
if (my_r != other_r) {
return my_r < other_r;
// compare variety amount
} else {
int my_v = this->variety();
int other_v = other.variety();
if (my_v != other_v) {
return my_v < other_v;
// both solutions are equal
} else {
return false;
}
}
}
}
void print(bool shortform=false) {
if (!shortform) {
std::cout << std::endl << "Solution" << std::endl;
for (auto it = this->Rods.begin(); it != this->Rods.end(); ++it) {
int pos = std::distance(this->Rods.begin(), it);
std::cout << "Rod " << pos << ": ";
for (auto c: (*it)->cuts()) {
std::cout << c->length() << " ";
}
std::cout << "(-" << (*it)->remainder() << ")" << std::endl;
}
}
std::cout << "Rods=" << this->rods();
std::cout << ", Remainder=" << this->remainder();
std::cout << ", Variety=" << this->variety();
std::cout << std::endl;
}
int remainder() const {
int ret = 0;
for (auto r: this->Rods) {
ret += r->remainder();
}
return ret;
}
int rods() const {
return (int) this->Rods.size();
}
int variety() const {
int ret = 0;
for (auto r: this->Rods) {
int v = r->variety();
if (v > 1) ret += v;
}
return ret;
}
private:
std::vector<std::shared_ptr<CutableRod>> Rods;
};
class CutRequest {
public:
CutRequest() {}
void add(int amount, int length) {
for (int i=0; i < amount; ++i) {
auto c = std::make_shared<Cut>(length);
this->Cuts.push_back(c);
}
}
void arrangeCuts() {
auto time_start = std::time(nullptr);
auto solution = CutSolution();
solution = this->arrangeCutIteration(solution, this->Cuts);
solution.print();
auto time_end = std::time(nullptr);
std::cout << "Duration: " << (time_end - time_start) << std::endl;
}
std::vector<std::shared_ptr<const Cut>> cuts() {
return this->Cuts;
}
private:
std::vector<std::shared_ptr<const Cut>> Cuts;
CutSolution arrangeCutIteration(CutSolution &current_solution,
std::vector<std::shared_ptr<const Cut>> remaining_cuts) {
if (remaining_cuts.empty()) return current_solution;
CutSolution best_solution;
bool ret_is_defined = false;
std::vector<int> tested_lengths;
for (int idx_try=0; idx_try < remaining_cuts.size(); ++idx_try) {
auto cut = remaining_cuts.at(idx_try);
// avaoid testing same length again
// if (std::find(tested_lengths.begin(), tested_lengths.end(), cut->length()) != tested_lengths.end()) continue;
if (intvectcontains(tested_lengths, cut->length())) continue;
tested_lengths.push_back(cut->length());
// create temporary solution for trial
CutSolution trysol(current_solution);
// add cut to temporary solution
trysol.addCut(cut);
// create list of remaining other cuts
std::vector<std::shared_ptr<const Cut>> remaining_cuts_without_try;
remaining_cuts_without_try.clear();
for (int idx_other=0; idx_other < remaining_cuts.size(); ++idx_other) {
if (idx_other == idx_try) continue;
auto cut_other = remaining_cuts.at(idx_other);
remaining_cuts_without_try.push_back(cut_other);
}
// solve for tried remaining cuts
trysol = this->arrangeCutIteration(trysol, remaining_cuts_without_try);
// keep best solution
if (!ret_is_defined || trysol.isBetterThan(best_solution)) {
best_solution = trysol;
if (current_solution.rods() == 0) {
std::cout << "Better Solution: ";
best_solution.print(true);
}
ret_is_defined = true;
}
}
return best_solution;
}
};
int main(void) {
CutRequest cr;
cr.add(8, 660);
cr.add(16, 620);
cr.add(1, 905);
cr.add(2, 442);
cr.add(2, 848);
cr.add(4, 414);
cr.arrangeCuts();
// // manual solve
// CutSolution cs;
// for (auto c: cr.cuts()) {
// cs.addCut(c);
// }
// cs.print();
return 0;
}