#include #include #include #include #include bool intvectcontains(const std::vector &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 cut) { assert(this->canAddCut(cut)); this->Cuts.push_back(cut); this->Remainder -= cut->length(); this->Remainder -= this->CutThickness; } bool canAddCut(std::shared_ptr cut) { return this->Remainder >= cut->length(); } std::vector> cuts() { return this->Cuts; } int remainder() { return this->Remainder; } int variety(void) { std::vector 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> Cuts; }; class CutSolution { public: CutSolution() { } CutSolution(CutSolution &other) { for (auto r_other: other.Rods) { auto r_copy = std::make_shared(*r_other); this->Rods.push_back(r_copy); } } void addCut(std::shared_ptr cut) { // add rod if empty if (this->Rods.empty()) { auto new_rod = std::make_shared(); this->Rods.push_back(new_rod); } // add rod if cannot add cut if (!this->Rods.back()->canAddCut(cut)) { auto new_rod = std::make_shared(); 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> Rods; }; class CutRequest { public: CutRequest() {} void add(int amount, int length) { for (int i=0; i < amount; ++i) { auto c = std::make_shared(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> cuts() { return this->Cuts; } private: std::vector> Cuts; CutSolution arrangeCutIteration(CutSolution ¤t_solution, std::vector> remaining_cuts) { if (remaining_cuts.empty()) return current_solution; CutSolution best_solution; bool ret_is_defined = false; std::vector 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> 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; }