287 lines
7.3 KiB
C++
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 ¤t_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;
|
|
}
|