Initial commit
This commit is contained in:
+32
@@ -0,0 +1,32 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#include "ArrayGraph.h"
|
||||
#include <iostream>
|
||||
|
||||
ArrayGraph::ArrayGraph(unsigned vertexNumber)
|
||||
{
|
||||
//ctor
|
||||
this->vertexNumber = vertexNumber;
|
||||
graphMatrix = new unsigned*[vertexNumber];
|
||||
graphArray = new unsigned[vertexNumber*vertexNumber];
|
||||
// W ten sposob cala tablica bedzie w pamieci w jednej czesci
|
||||
// (mniej chybien w odwolaniach procesora do cache)
|
||||
|
||||
for(int i = 0; i < vertexNumber; i++)
|
||||
{
|
||||
graphMatrix[i] = graphArray + i * vertexNumber;
|
||||
|
||||
for(int j = 0; j < vertexNumber; j++)
|
||||
graphMatrix[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayGraph::~ArrayGraph()
|
||||
{
|
||||
//dtor
|
||||
delete graphArray;
|
||||
delete graphMatrix;
|
||||
}
|
||||
|
||||
bool ArrayGraph::addEdge(unsigned v, unsigned w, unsigned weight)
|
||||
{
|
||||
if(weight >= 1000)
|
||||
// Waga krawedzi musi byc mniejsza od 1000
|
||||
weight = 900;
|
||||
|
||||
if(graphMatrix[v][w] > 0)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
graphMatrix[v][w] = weight;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ArrayGraph::removeEdge(unsigned v, unsigned w)
|
||||
{
|
||||
if(graphMatrix[v][w] == 0)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
graphMatrix[v][w] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned ArrayGraph::getWeight(unsigned v, unsigned w)
|
||||
{
|
||||
return graphMatrix[v][w];
|
||||
}
|
||||
|
||||
void ArrayGraph::displayGraph()
|
||||
{
|
||||
for(int i = 0; i < vertexNumber; i++)
|
||||
{
|
||||
for(int j = 0; j < vertexNumber; j++)
|
||||
{
|
||||
std::cout << graphMatrix[i][j] << '\t';
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#ifndef ARRAYGRAPH_H
|
||||
#define ARRAYGRAPH_H
|
||||
|
||||
#include "Graph.h"
|
||||
|
||||
class ArrayGraph : public Graph
|
||||
{
|
||||
public:
|
||||
ArrayGraph(unsigned vertexNumber);
|
||||
virtual ~ArrayGraph();
|
||||
bool addEdge(unsigned v, unsigned w, unsigned weight);
|
||||
bool removeEdge(unsigned v, unsigned w);
|
||||
unsigned getWeight(unsigned v, unsigned w);
|
||||
void displayGraph();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
unsigned **graphMatrix;
|
||||
unsigned *graphArray;
|
||||
|
||||
};
|
||||
|
||||
#endif // ARRAYGRAPH_H
|
||||
@@ -0,0 +1,681 @@
|
||||
#include "Graph.h"
|
||||
#include "Stopwatch.h"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <queue>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
Graph::Graph()
|
||||
{
|
||||
//ctor
|
||||
}
|
||||
|
||||
Graph::~Graph()
|
||||
{
|
||||
//dtor
|
||||
}
|
||||
|
||||
unsigned Graph::getVertexNumber()
|
||||
{
|
||||
return vertexNumber;
|
||||
}
|
||||
|
||||
void Graph::randomGenerateFullGraph(Graph &graph, unsigned maxWeight)
|
||||
{
|
||||
std::random_device randomSrc;
|
||||
std::default_random_engine randomGen(randomSrc());
|
||||
std::uniform_int_distribution<> weightDist(1, maxWeight);
|
||||
|
||||
for(int i = 0; i < graph.vertexNumber; i++)
|
||||
{
|
||||
for(int j = 0; j < graph.vertexNumber; j++)
|
||||
{
|
||||
if(i != j)
|
||||
{
|
||||
// Bez warunku na krawedzie juz wygenerowane...
|
||||
// ...z tym radzi sobie juz metoda addEdge
|
||||
int randomWeight = weightDist(randomGen);
|
||||
graph.addEdge(i, j, randomWeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned> Graph::travellingSalesmanBruteForce(Graph &graph)
|
||||
{
|
||||
// ALGORYTM przegladu zupelnego
|
||||
// Implementacja: Jan Potocki 2017
|
||||
// (refactoring 2019)
|
||||
std::vector<unsigned> vertexArray;
|
||||
|
||||
// Generowanie "spisu" wierzcholkow
|
||||
// (od razu w odpowiedniej kolejnosci dla next_permutation)
|
||||
for(int i = 1; i < graph.vertexNumber; i++)
|
||||
vertexArray.push_back(i);
|
||||
|
||||
std::vector<unsigned> minCombination;
|
||||
int minRoute = -1;
|
||||
|
||||
// Petla przegladajaca kolejne permutacje
|
||||
do
|
||||
{
|
||||
std::vector<unsigned> combination;
|
||||
|
||||
// Dodanie wierzcholka startowego i pierwszego na trasie
|
||||
combination.push_back(0);
|
||||
combination.push_back(vertexArray.front());
|
||||
|
||||
// W petli reszta wiercholkow
|
||||
for(int i = 1; i < vertexArray.size(); i++)
|
||||
combination.push_back(vertexArray.at(i));
|
||||
|
||||
// Powrot do wierzcholka startowego
|
||||
combination.push_back(0);
|
||||
// PEA 2
|
||||
// Jan Potocki 2017
|
||||
|
||||
int route = 0;
|
||||
for(int i = 1; i < combination.size(); i++)
|
||||
route += graph.getWeight(combination.at(i - 1), combination.at(i));
|
||||
|
||||
if(minRoute == -1 || route < minRoute)
|
||||
{
|
||||
minRoute = route;
|
||||
minCombination = combination;
|
||||
}
|
||||
}
|
||||
while(next_permutation(vertexArray.begin(), vertexArray.end()));
|
||||
|
||||
return minCombination;
|
||||
}
|
||||
|
||||
std::vector<unsigned> Graph::travellingSalesmanBranchAndBound(Graph &graph)
|
||||
{
|
||||
// ALGORYTM pracujacy w oparciu o kolejke priorytetowa i niejawnie utworzone drzewo
|
||||
// Zrodlo: www.ii.uni.wroc.pl/~prz/2011lato/ah/opracowania/met_podz_ogr.opr.pdf
|
||||
// Autor: Mateusz Lyczek 2011
|
||||
// Implementacja: Jan Potocki 2017
|
||||
std::priority_queue<std::vector<unsigned>, std::vector< std::vector<unsigned> >, RouteComparison> routeQueue;
|
||||
std::vector<unsigned> optimalRoute; // Tu bedziemy zapisywac optymalne (w danej chwili) rozwiazanie
|
||||
int optimalRouteLength = -1; // -1 - bedziemy odtad uznawac, ze to jest nieskonczonosc ;-)
|
||||
|
||||
// UMOWA
|
||||
// Pierwszy element wektora to dlugosc trasy (trzeba ustawic "z palca"!)
|
||||
// Kolejne to wierzcholki na trasie
|
||||
std::vector<unsigned> currentRoute; // Niejawne tworzenie drzewa, tu bedzie korzen
|
||||
currentRoute.push_back(0); // Poczatkowe oszacowanie nie ma znaczenia
|
||||
currentRoute.push_back(0); // Wierzcholek startowy (korzen drzewa rozwiazan)
|
||||
routeQueue.push(currentRoute); // Dodanie do kolejki korzenia
|
||||
|
||||
while(!routeQueue.empty())
|
||||
{
|
||||
// Przypisanie korzenia do dalszej roboty
|
||||
currentRoute = routeQueue.top();
|
||||
routeQueue.pop();
|
||||
|
||||
// Sprawdzenie, czy rozwiazanie jest warte rozwijania, czy odrzucic
|
||||
if(optimalRouteLength == -1 || currentRoute.at(0) < optimalRouteLength)
|
||||
{
|
||||
for(int i = 0; i < graph.vertexNumber; i++)
|
||||
{
|
||||
// Petla wykonywana dla kazdego potomka rozpatrywanego wlasnie rozwiazania w drzewie
|
||||
// Ustalenie, czy dany wierzcholek mozna jeszcze wykorzystac, czy juz zostal uzyty
|
||||
bool vertexUsed = false;
|
||||
for(int j = 1; j < currentRoute.size(); j++)
|
||||
{
|
||||
if(currentRoute.at(j) == i)
|
||||
{
|
||||
vertexUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(vertexUsed)
|
||||
continue;
|
||||
|
||||
// Niejawne utworzenie nowego wezla reprezuntujacego rozpatrywane rozwiazanie...
|
||||
std::vector<unsigned> nextRoute = currentRoute;
|
||||
//unsigned nextLength = graph.getWeight(nextRoute.back(), i);
|
||||
nextRoute.push_back(i);
|
||||
|
||||
// Dalej bedziemy postepowac roznie...
|
||||
if(nextRoute.size() > graph.vertexNumber)
|
||||
{
|
||||
// Doszlismy wlasnie do liscia
|
||||
// Dodajemy droge powrotna, nie musimy nic szacowac
|
||||
// (wszystko juz wiemy)
|
||||
nextRoute.push_back(0);
|
||||
|
||||
nextRoute.at(0) = 0;
|
||||
|
||||
for(int j = 1; j < nextRoute.size() - 1; j++)
|
||||
{
|
||||
// Liczymy dystans od poczatku do konca
|
||||
nextRoute.at(0) += graph.getWeight(nextRoute.at(j), nextRoute.at(j+ 1));
|
||||
}
|
||||
if(optimalRouteLength == -1 || nextRoute.at(0) < optimalRouteLength)
|
||||
{
|
||||
optimalRouteLength = nextRoute.at(0);
|
||||
nextRoute.erase(nextRoute.begin());
|
||||
optimalRoute = nextRoute;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Liczenie tego, co juz wiemy, od nowa...
|
||||
// (dystans od poczatku)
|
||||
nextRoute.at(0) = 0;
|
||||
for(int j = 1; j < nextRoute.size() - 1; j++)
|
||||
{
|
||||
nextRoute.at(0) += graph.getWeight(nextRoute.at(j), nextRoute.at(j + 1));
|
||||
}
|
||||
|
||||
// Reszte szacujemy...
|
||||
// Pomijamy od razu wierzcholek startowy
|
||||
for(int j = 1; j < graph.vertexNumber; j++)
|
||||
{
|
||||
// Odrzucenie wierzcholkow juz umieszczonych na trasie
|
||||
bool vertexUsed = false;
|
||||
for(int k = 1; k < currentRoute.size(); k++)
|
||||
{
|
||||
if(j == currentRoute.at(k))
|
||||
{
|
||||
vertexUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(vertexUsed)
|
||||
continue;
|
||||
|
||||
int minEdge = -1;
|
||||
for(int k = 0; k < graph.vertexNumber; k++)
|
||||
{
|
||||
// Odrzucenie krawedzi do wierzcholka 0 przy ostatnim wierzcholku w czesciowym rozwiazaniu
|
||||
// Wyjatkiem jest ostatnia mozliwa krawedz
|
||||
if(j == i && k == 0)
|
||||
continue;
|
||||
|
||||
// Odrzucenie krawedzi do wierzcholka umieszczonego juz na rozwazanej trasie
|
||||
bool vertexUsed = false;
|
||||
for(int l = 2; l < nextRoute.size(); l++)
|
||||
{
|
||||
if(k == nextRoute.at(l))
|
||||
{
|
||||
vertexUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(vertexUsed)
|
||||
continue;
|
||||
|
||||
// Odrzucenie samego siebie
|
||||
if(k == j)
|
||||
continue;
|
||||
|
||||
// Znalezienie najkrotszej mozliwej jeszcze do uzycia krawedzi
|
||||
unsigned consideredLength = graph.getWeight(j, k);
|
||||
|
||||
if(minEdge == -1)
|
||||
minEdge = consideredLength;
|
||||
else if(minEdge > consideredLength)
|
||||
minEdge = consideredLength;
|
||||
}
|
||||
nextRoute.at(0) += minEdge;
|
||||
}
|
||||
|
||||
// ...i teraz zastanawiamy sie co dalej
|
||||
if(optimalRouteLength == -1 || nextRoute.at(0) < optimalRouteLength)
|
||||
{
|
||||
routeQueue.push(nextRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Jezeli jedno rozwiazanie odrzucilismy, to wszystkie inne tez mozemy
|
||||
// (kolejka priorytetowa, inne nie moga byc lepsze)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return optimalRoute;
|
||||
}
|
||||
|
||||
std::vector<unsigned> Graph::travellingSalesmanGreedy(Graph &graph, unsigned startVertex)
|
||||
{
|
||||
// ALGORYTM zachlanny z wierzcholkiem startowym przekazanym w parametrze
|
||||
// Implementacja: Jan Potocki 2017
|
||||
std::vector<unsigned> route;
|
||||
|
||||
// std::random_device randomSrc;
|
||||
// std::default_random_engine randomGen(randomSrc());
|
||||
// std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
|
||||
|
||||
// Losowanie wierzcholka startowego
|
||||
//route.push_back(vertexDist(randomGen));
|
||||
route.push_back(startVertex);
|
||||
|
||||
for(int i = 0; i < graph.vertexNumber - 1; i++)
|
||||
{
|
||||
int minEdge = -1;
|
||||
unsigned nextVertex;
|
||||
for(int j = 0; j < graph.vertexNumber; j++)
|
||||
{
|
||||
// Odrzucenie samego siebie lub wierzcholka startowego
|
||||
// (zeby bylo szybciej)
|
||||
if(route.back() == j || route.front() == j)
|
||||
continue;
|
||||
|
||||
// Odrzucenie krawedzi do wierzcholka umieszczonego juz na trasie
|
||||
bool vertexUsed = false;
|
||||
for(int k = 0; k < route.size(); k++)
|
||||
{
|
||||
if(j == route.at(k))
|
||||
{
|
||||
vertexUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(vertexUsed)
|
||||
continue;
|
||||
|
||||
// Znalezienie najkrotszej mozliwej jeszcze do uzycia krawedzi
|
||||
unsigned consideredLength = graph.getWeight(route.back(), j);
|
||||
|
||||
if(minEdge == -1)
|
||||
{
|
||||
minEdge = consideredLength;
|
||||
nextVertex = j;
|
||||
}
|
||||
else if(minEdge > consideredLength)
|
||||
{
|
||||
minEdge = consideredLength;
|
||||
nextVertex = j;
|
||||
}
|
||||
}
|
||||
route.push_back(nextVertex);
|
||||
}
|
||||
|
||||
route.push_back(startVertex);
|
||||
return route;
|
||||
}
|
||||
|
||||
std::vector<unsigned> Graph::travellingSalesmanHybrid(Graph &graph)
|
||||
{
|
||||
// ALGORYTM hybrydowy losowo-zachlanny
|
||||
// Losowa czesc wierzcholkow jest losowana, reszta zachlannie
|
||||
// Implementacja: Jan Potocki 2019
|
||||
std::vector<unsigned> route;
|
||||
|
||||
std::random_device randomSrc;
|
||||
std::default_random_engine randomGen(randomSrc());
|
||||
std::uniform_int_distribution<> vertexNumberDist(1, graph.vertexNumber);
|
||||
std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
|
||||
|
||||
// Liczba losowanych wierzcholkow
|
||||
unsigned randomVertexNumber = vertexNumberDist(randomGen);
|
||||
|
||||
// Czesc losowa
|
||||
for(int i = 0; i < randomVertexNumber; i++)
|
||||
{
|
||||
unsigned randomVertex;
|
||||
bool vertexUsed;
|
||||
|
||||
do
|
||||
{
|
||||
randomVertex = vertexDist(randomGen);
|
||||
vertexUsed = false;
|
||||
|
||||
for(int j = 0; j < route.size(); j++)
|
||||
{
|
||||
if(route.at(j) == randomVertex)
|
||||
{
|
||||
vertexUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(vertexUsed == true);
|
||||
|
||||
route.push_back(randomVertex);
|
||||
}
|
||||
|
||||
// Czesc zachlanna
|
||||
for(int i = 0; i < graph.vertexNumber - randomVertexNumber; i++)
|
||||
{
|
||||
int minEdge = -1;
|
||||
unsigned nextVertex;
|
||||
for(int j = 0; j < graph.vertexNumber; j++)
|
||||
{
|
||||
// Odrzucenie samego siebie lub wierzcholka startowego
|
||||
// (zeby bylo szybciej)
|
||||
if(route.back() == j || route.front() == j)
|
||||
continue;
|
||||
|
||||
// Odrzucenie krawedzi do wierzcholka umieszczonego juz na trasie
|
||||
bool vertexUsed = false;
|
||||
for(int k = 0; k < route.size(); k++)
|
||||
{
|
||||
if(j == route.at(k))
|
||||
{
|
||||
vertexUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(vertexUsed)
|
||||
continue;
|
||||
|
||||
// Znalezienie najkrotszej mozliwej jeszcze do uzycia krawedzi
|
||||
unsigned consideredLength = graph.getWeight(route.back(), j);
|
||||
|
||||
if(minEdge == -1)
|
||||
{
|
||||
minEdge = consideredLength;
|
||||
nextVertex = j;
|
||||
}
|
||||
else if(minEdge > consideredLength)
|
||||
{
|
||||
minEdge = consideredLength;
|
||||
nextVertex = j;
|
||||
}
|
||||
}
|
||||
route.push_back(nextVertex);
|
||||
}
|
||||
|
||||
route.push_back(route.front());
|
||||
return route;
|
||||
}
|
||||
|
||||
std::vector<unsigned> Graph::travellingSalesmanRandom(Graph &graph)
|
||||
{
|
||||
// ALGORYTM losowy
|
||||
// Implementacja: Jan Potocki 2019
|
||||
std::vector<unsigned> route;
|
||||
|
||||
std::random_device randomSrc;
|
||||
std::default_random_engine randomGen(randomSrc());
|
||||
std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
|
||||
|
||||
for(int i = 0; i < graph.vertexNumber; i++)
|
||||
{
|
||||
unsigned randomVertex;
|
||||
bool vertexUsed;
|
||||
|
||||
do
|
||||
{
|
||||
randomVertex = vertexDist(randomGen);
|
||||
vertexUsed = false;
|
||||
|
||||
for(int j = 0; j < route.size(); j++)
|
||||
{
|
||||
if(route.at(j) == randomVertex)
|
||||
{
|
||||
vertexUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(vertexUsed == true);
|
||||
|
||||
route.push_back(randomVertex);
|
||||
}
|
||||
|
||||
route.push_back(route.front());
|
||||
return route;
|
||||
}
|
||||
|
||||
std::vector<unsigned> Graph::travellingSalesmanTabuSearch(Graph &graph, unsigned tabuSteps, bool diversification, int iterationsToRestart, unsigned minStopTime, unsigned threadsNumber)
|
||||
{
|
||||
// ALGORYTM wielawotkowy oparty na metaheurystyce tabu search
|
||||
// Pomocniczy kod uruchamiajacy watki wlasciwego algorytmu w najbardziej optymalny sposob
|
||||
// Implementacja: Jan Potocki 2019
|
||||
std::vector<unsigned> startVertexVector;
|
||||
std::vector<std::thread> threadsVector;
|
||||
std::vector<std::vector<unsigned>> resultsVector(threadsNumber);
|
||||
std::vector<int> resultsLength(threadsNumber);
|
||||
std::vector<unsigned> optimalResult;
|
||||
int optimalResultIndex;
|
||||
int optimalResultLength;
|
||||
|
||||
std::random_device randomSrc;
|
||||
std::default_random_engine randomGen(randomSrc());
|
||||
std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
|
||||
|
||||
for(int i = 0; i < threadsNumber; i++)
|
||||
{
|
||||
std::vector<unsigned> startRoute;
|
||||
unsigned startVertex;
|
||||
bool startVertexUsed;
|
||||
|
||||
if(i < graph.vertexNumber)
|
||||
{
|
||||
do
|
||||
{
|
||||
startVertex = vertexDist(randomGen);
|
||||
startVertexUsed = false;
|
||||
|
||||
for(int j = 0; j < startVertexVector.size(); j++)
|
||||
{
|
||||
if(startVertexVector.at(j) == startVertex)
|
||||
{
|
||||
startVertexUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(startVertexUsed == true);
|
||||
|
||||
startVertexVector.push_back(startVertex);
|
||||
startRoute = Graph::travellingSalesmanGreedy(graph, startVertex);
|
||||
}
|
||||
else
|
||||
{
|
||||
startRoute = Graph::travellingSalesmanRandom(graph);
|
||||
}
|
||||
|
||||
threadsVector.push_back(std::thread(Graph::travellingSalesmanTabuSearchEngine, std::ref(graph), tabuSteps, diversification, iterationsToRestart, minStopTime, startRoute, std::ref(resultsVector.at(i)), std::ref(resultsLength.at(i))));
|
||||
}
|
||||
|
||||
for(int i = 0; i < threadsNumber; i++)
|
||||
threadsVector.at(i).join();
|
||||
|
||||
optimalResultIndex = 0;
|
||||
optimalResultLength = resultsLength.at(0);
|
||||
|
||||
for(int i = 0; i < threadsNumber; i++)
|
||||
{
|
||||
if(resultsLength.at(i) < optimalResultLength)
|
||||
{
|
||||
optimalResultIndex = i;
|
||||
optimalResultLength = resultsLength.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
optimalResult = resultsVector.at(optimalResultIndex);
|
||||
|
||||
return optimalResult;
|
||||
}
|
||||
|
||||
void Graph::travellingSalesmanTabuSearchEngine(Graph &graph, unsigned tabuSteps, bool diversification, int iterationsToRestart, unsigned minStopTime, std::vector<unsigned> startRoute, std::vector<unsigned> &result, int &resultLength)
|
||||
{
|
||||
// ALGORYTM oparty na metaheurystyce tabu search z dywersyfikacja i sasiedztwem typu swap
|
||||
// Rdzen przeznaczony do uruchamiania jako jeden watek
|
||||
// Projekt i implementacja: Jan Potocki 2017
|
||||
// (refactoring 2019)
|
||||
Stopwatch onboardClock;
|
||||
|
||||
std::vector<unsigned> optimalRoute; // Tu bedziemy zapisywac optymalne (w danej chwili) rozwiazanie
|
||||
int optimalRouteLength = -1; // -1 - bedziemy odtad uznawac, ze to jest nieskonczonosc ;-)
|
||||
std::vector<unsigned> currentRoute; // Rozpatrywane rozwiazanie
|
||||
|
||||
// Wyznaczenie poczatkowego rozwiazania algorytmem zachlannym
|
||||
//currentRoute = Graph::travellingSalesmanGreedy(graph);
|
||||
currentRoute = startRoute;
|
||||
|
||||
// Inicjalizacja glownej petli...
|
||||
std::vector< std::vector<unsigned> > tabuArray;
|
||||
unsigned currentTabuSteps = tabuSteps;
|
||||
int stopCounter = 0;
|
||||
bool timeNotExceeded = true;
|
||||
onboardClock.start();
|
||||
|
||||
// Rdzen algorytmu
|
||||
while(timeNotExceeded == true)
|
||||
{
|
||||
bool cheeseSupplied = true;
|
||||
bool intensification = false;
|
||||
|
||||
while(cheeseSupplied == true)
|
||||
{
|
||||
std::vector<unsigned> nextRoute;
|
||||
int nextRouteLength = -1;
|
||||
|
||||
std::vector<unsigned> nextTabu(3, 0);
|
||||
nextTabu.at(0) = currentTabuSteps;
|
||||
|
||||
// Generowanie sasiedztwa typu swap przez zamiane wierzcholkow
|
||||
// (wierzcholka startowego i zarazem ostatniego nie ruszamy,
|
||||
// pomijamy tez od razu aktualny wierzcholek)
|
||||
for(int i = 1; i < graph.vertexNumber - 1; i++)
|
||||
{
|
||||
for(int j = i + 1; j < graph.vertexNumber; j++)
|
||||
{
|
||||
std::vector<unsigned> neighbourRoute = currentRoute;
|
||||
|
||||
// Zamiana
|
||||
unsigned buffer = neighbourRoute.at(j);
|
||||
neighbourRoute.at(j) = neighbourRoute.at(i);
|
||||
neighbourRoute.at(i) = buffer;
|
||||
|
||||
unsigned neighbourRouteLength = 0;
|
||||
for(int i = 1; i < neighbourRoute.size(); i++)
|
||||
neighbourRouteLength += graph.getWeight(neighbourRoute.at(i - 1), neighbourRoute.at(i));
|
||||
|
||||
// Sprawdzenie, czy dany ruch nie jest na liscie tabu
|
||||
// (dwa wierzcholki)
|
||||
bool tabu = false;
|
||||
for(int k = 0; k < tabuArray.size(); k++)
|
||||
{
|
||||
if(tabuArray.at(k).at(1) == i && tabuArray.at(k).at(2) == j)
|
||||
{
|
||||
tabu = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(tabuArray.at(k).at(1) == j && tabuArray.at(k).at(2) == i)
|
||||
{
|
||||
tabu = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Kryterium aspiracji...
|
||||
if(tabu == true && neighbourRouteLength >= optimalRouteLength)
|
||||
// ...jezeli niespelnione - pomijamy ruch
|
||||
continue;
|
||||
|
||||
if(nextRouteLength == -1)
|
||||
{
|
||||
nextRouteLength = neighbourRouteLength;
|
||||
nextRoute = neighbourRoute;
|
||||
nextTabu.at(1) = i;
|
||||
nextTabu.at(2) = j;
|
||||
}
|
||||
else if(nextRouteLength > neighbourRouteLength)
|
||||
{
|
||||
nextRouteLength = neighbourRouteLength;
|
||||
nextRoute = neighbourRoute;
|
||||
nextTabu.at(1) = i;
|
||||
nextTabu.at(2) = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentRoute = nextRoute;
|
||||
|
||||
if(optimalRouteLength == -1)
|
||||
{
|
||||
optimalRouteLength = nextRouteLength;
|
||||
optimalRoute = nextRoute;
|
||||
|
||||
// Reset licznika
|
||||
stopCounter = 0;
|
||||
}
|
||||
else if(optimalRouteLength > nextRouteLength)
|
||||
{
|
||||
optimalRouteLength = nextRouteLength;
|
||||
optimalRoute = nextRoute;
|
||||
|
||||
// Zaplanowanie intensyfikacji
|
||||
intensification = true;
|
||||
|
||||
// Reset licznika
|
||||
stopCounter = 0;
|
||||
}
|
||||
|
||||
// Weryfikacja listy tabu...
|
||||
// ...aktualizacja kadencji na liscie tabu
|
||||
for(int i = 0; i < tabuArray.size(); i++)
|
||||
{
|
||||
tabuArray.at(i).at(0)--;
|
||||
}
|
||||
|
||||
//...usuniecie zerowych kadencji
|
||||
for(int i = 0; i < tabuArray.size(); i++)
|
||||
{
|
||||
if(tabuArray.at(i).at(0) == 0)
|
||||
tabuArray.erase(tabuArray.begin() + i);
|
||||
}
|
||||
|
||||
// ...dopisanie ostatniego ruchu do listy tabu
|
||||
tabuArray.push_back(nextTabu);
|
||||
|
||||
// Zliczenie iteracji
|
||||
stopCounter++;
|
||||
|
||||
// Zmierzenie czasu
|
||||
onboardClock.stop();
|
||||
if(onboardClock.read() > minStopTime)
|
||||
timeNotExceeded = false;
|
||||
|
||||
// Sprawdzenie warunku zatrzymania
|
||||
if(diversification == true)
|
||||
{
|
||||
// Przy aktywowanej dywersyfikacji - po zadanej liczbie iteracji bez poprawy
|
||||
if(stopCounter >= iterationsToRestart || timeNotExceeded == false)
|
||||
cheeseSupplied = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Przy nieaktywowanej dywersyfikacji - po uplynieciu okreslonego czasu
|
||||
if(timeNotExceeded == false)
|
||||
cheeseSupplied = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Dywersyfikacja
|
||||
if(diversification == true)
|
||||
{
|
||||
if(intensification == true)
|
||||
{
|
||||
// Intensyfikacja przeszukiwania przy ostatnim minimum
|
||||
currentRoute = optimalRoute;
|
||||
currentTabuSteps = tabuSteps / 4;
|
||||
intensification = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Algorytm hybrydowy losowo-zachlanny
|
||||
currentRoute = Graph::travellingSalesmanHybrid(graph);
|
||||
currentTabuSteps = tabuSteps;
|
||||
intensification = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset licznika iteracji przed restartem
|
||||
stopCounter = 0;
|
||||
}
|
||||
|
||||
result = optimalRoute;
|
||||
resultLength = optimalRouteLength;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef GRAPH_H
|
||||
#define GRAPH_H
|
||||
#include <vector>
|
||||
|
||||
|
||||
class Graph
|
||||
{
|
||||
public:
|
||||
Graph();
|
||||
virtual ~Graph();
|
||||
virtual bool addEdge(unsigned v, unsigned w, unsigned weight) = 0;
|
||||
virtual bool removeEdge(unsigned v, unsigned w) = 0;
|
||||
virtual unsigned getWeight(unsigned v, unsigned w) = 0;
|
||||
unsigned getVertexNumber();
|
||||
virtual void displayGraph() = 0;
|
||||
static void randomGenerateFullGraph(Graph &graph, unsigned maxWeight);
|
||||
static std::vector<unsigned> travellingSalesmanBruteForce(Graph &graph);
|
||||
static std::vector<unsigned> travellingSalesmanBranchAndBound(Graph &graph);
|
||||
static std::vector<unsigned> travellingSalesmanGreedy(Graph &graph, unsigned startVertex);
|
||||
static std::vector<unsigned> travellingSalesmanHybrid(Graph &graph);
|
||||
static std::vector<unsigned> travellingSalesmanRandom(Graph &graph);
|
||||
static std::vector<unsigned> travellingSalesmanTabuSearch(Graph &graph, unsigned tabuSteps, bool diversification, int iterationsToRestart, unsigned minStopTime, unsigned threadsNumber);
|
||||
|
||||
protected:
|
||||
unsigned vertexNumber;
|
||||
|
||||
private:
|
||||
static void travellingSalesmanTabuSearchEngine(Graph &graph, unsigned tabuSteps, bool diversification, int iterationsToRestart, unsigned minStopTime, std::vector<unsigned> startRoute, std::vector<unsigned> &result, int &resultLength);
|
||||
|
||||
class RouteComparison
|
||||
{
|
||||
public:
|
||||
bool operator() (const std::vector<unsigned>& lhs, const std::vector<unsigned>& rhs) const
|
||||
{
|
||||
return (lhs.at(0) > rhs.at(0));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif // GRAPH_H
|
||||
Executable
+167
@@ -0,0 +1,167 @@
|
||||
#include "ListGraph.h"
|
||||
#include <iostream>
|
||||
|
||||
ListGraph::ListGraph(unsigned vertexNumber)
|
||||
{
|
||||
//ctor
|
||||
this->vertexNumber = vertexNumber;
|
||||
graphList = new element*[vertexNumber];
|
||||
|
||||
for(int i = 0; i < vertexNumber; i++)
|
||||
graphList[i] = NULL;
|
||||
}
|
||||
|
||||
ListGraph::~ListGraph()
|
||||
{
|
||||
//dtor
|
||||
for(int i = 0; i < vertexNumber; i++)
|
||||
{
|
||||
if(graphList[i] != NULL)
|
||||
{
|
||||
element *position = graphList[i];
|
||||
do
|
||||
{
|
||||
element *next = position->next;
|
||||
delete position;
|
||||
position = next;
|
||||
}
|
||||
while(position != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] graphList;
|
||||
}
|
||||
|
||||
bool ListGraph::addEdge(unsigned v, unsigned w, unsigned weight)
|
||||
{
|
||||
if(weight >= 1000)
|
||||
// Waga krawedzi musi byc mniejsza od 1000
|
||||
weight = 900;
|
||||
|
||||
if(graphList[v] == NULL)
|
||||
{
|
||||
graphList[v] = new element;
|
||||
graphList[v]->vertex = w;
|
||||
graphList[v]->weight = weight;
|
||||
graphList[v]->next = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isAlready = false;
|
||||
element *next = graphList[v];
|
||||
element *position = NULL;
|
||||
do
|
||||
{
|
||||
position = next;
|
||||
next = next->next;
|
||||
if(position->vertex == w)
|
||||
{
|
||||
isAlready = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(next != NULL);
|
||||
|
||||
if(!isAlready)
|
||||
{
|
||||
element *newEdge = new element;
|
||||
newEdge->vertex = w;
|
||||
newEdge->weight = weight;
|
||||
newEdge->next = NULL;
|
||||
position->next = newEdge;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ListGraph::removeEdge(unsigned v, unsigned w)
|
||||
{
|
||||
if(graphList[v] == NULL)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
bool isAlready = false;
|
||||
element *next = graphList[v];
|
||||
element *position = NULL;
|
||||
element *prev = NULL;
|
||||
do
|
||||
{
|
||||
prev = position;
|
||||
position = next;
|
||||
next = next->next;
|
||||
if(position->vertex == w)
|
||||
{
|
||||
isAlready = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(next != NULL);
|
||||
|
||||
if(!isAlready)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
delete position;
|
||||
if(prev != NULL)
|
||||
prev->next = next;
|
||||
else
|
||||
graphList[v] = next;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned ListGraph::getWeight(unsigned v, unsigned w)
|
||||
{
|
||||
if(graphList[v] == NULL)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
bool isAlready = false;
|
||||
element *next = graphList[v];
|
||||
element *position = NULL;
|
||||
do
|
||||
{
|
||||
position = next;
|
||||
next = next->next;
|
||||
if(position->vertex == w)
|
||||
{
|
||||
isAlready = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(next != NULL);
|
||||
|
||||
if(!isAlready)
|
||||
return 0;
|
||||
else
|
||||
return position->weight;
|
||||
}
|
||||
}
|
||||
|
||||
void ListGraph::displayGraph()
|
||||
{
|
||||
for(int i = 0; i < vertexNumber; i++)
|
||||
{
|
||||
std::cout << i << " -> ";
|
||||
if(graphList[i] != NULL)
|
||||
{
|
||||
element *next = graphList[i];
|
||||
element *position = NULL;
|
||||
do
|
||||
{
|
||||
position = next;
|
||||
next = next->next;
|
||||
std::cout << position->vertex << '@' << position->weight << ' ';
|
||||
}
|
||||
while(next != NULL);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#ifndef LISTGRAPH_H
|
||||
#define LISTGRAPH_H
|
||||
|
||||
#include "Graph.h"
|
||||
|
||||
class ListGraph : public Graph
|
||||
{
|
||||
public:
|
||||
ListGraph(unsigned vertexNumber);
|
||||
virtual ~ListGraph();
|
||||
bool addEdge(unsigned v, unsigned w, unsigned weight);
|
||||
bool removeEdge(unsigned v, unsigned w);
|
||||
unsigned getWeight(unsigned v, unsigned w);
|
||||
void displayGraph();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
struct element
|
||||
{
|
||||
unsigned vertex;
|
||||
int weight;
|
||||
element *next;
|
||||
};
|
||||
element **graphList;
|
||||
|
||||
};
|
||||
|
||||
#endif // LISTGRAPH_H
|
||||
@@ -0,0 +1,24 @@
|
||||
CXXFLAGS = -O3 -Wall -std=c++11
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
detected_OS := Windows
|
||||
else
|
||||
detected_OS := $(shell uname)
|
||||
endif
|
||||
ifeq ($(detected_OS),Darwin)
|
||||
CXXFLAGS += -stdlib=libc++
|
||||
endif
|
||||
|
||||
OBJS = pea2plus.o ArrayGraph.o Graph.o ListGraph.o Stopwatch.o
|
||||
|
||||
LIBS = -pthread
|
||||
|
||||
TARGET = pea2plus
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CXX) -o $(TARGET) $(OBJS) $(LIBS)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(TARGET)
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#include "Stopwatch.h"
|
||||
|
||||
Stopwatch::Stopwatch()
|
||||
{
|
||||
//ctor
|
||||
// Jan Potocki 2017-2019
|
||||
}
|
||||
|
||||
void Stopwatch::start()
|
||||
{
|
||||
tstart = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void Stopwatch::stop()
|
||||
{
|
||||
tstop = std::chrono::steady_clock::now();
|
||||
measurement = tstop - tstart;
|
||||
}
|
||||
|
||||
double Stopwatch::read()
|
||||
{
|
||||
return measurement.count();
|
||||
}
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#ifndef STOPWATCH_H
|
||||
#define STOPWATCH_H
|
||||
|
||||
#include <chrono>
|
||||
|
||||
// Klasa do pomiaru czasu (wieloplatformowa)
|
||||
// Jan Potocki 2017-2019
|
||||
class Stopwatch
|
||||
{
|
||||
public:
|
||||
Stopwatch();
|
||||
void start();
|
||||
void stop();
|
||||
double read();
|
||||
protected:
|
||||
private:
|
||||
std::chrono::duration<double> measurement;
|
||||
std::chrono::time_point<std::chrono::steady_clock> tstart;
|
||||
std::chrono::time_point<std::chrono::steady_clock> tstop;
|
||||
};
|
||||
|
||||
#endif // STOPWATCH_H
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
+511
@@ -0,0 +1,511 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include "Stopwatch.h"
|
||||
#include "ArrayGraph.h"
|
||||
#include "ListGraph.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// USTAWIENIA
|
||||
// Liczba powtorzen automatycznych pomiarow do usrednienia
|
||||
const int measureIterations = 10;
|
||||
// liczba automatycznych pomiarow
|
||||
const int measureNumber = 4;
|
||||
// Czas zatrzymania algorytmu tabu search w kazdym z automatycznych pomiarow
|
||||
const int measureTabuStop[4] = {1, 5, 10, 15};
|
||||
// Maksymalna odleglosc miast przy automatycznym generowaniu
|
||||
const int measureSalesmanDistance = 400;
|
||||
|
||||
// Kadencja tabu search
|
||||
const int tabuLength = 30;
|
||||
// Kryterium dywersyfikacji, liczba iteracji bez poprawy
|
||||
const int tabuIterationsToRestart = 10000;
|
||||
|
||||
// Wykorzystanie reprezentacji grafu w postaci list sasiedztwa...
|
||||
// ...zamiast (domyslnie) macierzy sasiedztwa
|
||||
// (wolniejsze obliczenia, mniejsze uzycie pamieci)
|
||||
const bool useListGraph = false;
|
||||
|
||||
// Liczba watkow tabu search
|
||||
const unsigned tabuThreadsNumber = 2;
|
||||
|
||||
// Domyslny czas zatrzymania algorytmu tabu search [s]
|
||||
int tabuStopTime = 60;
|
||||
|
||||
// Domyslny stan dywersyfikacji
|
||||
bool tabuDiversification = true;
|
||||
|
||||
int main()
|
||||
{
|
||||
Stopwatch clock; // czasomierz
|
||||
Graph *graph = NULL; // <- tu bedziemy zapisywac adresy przez caly program
|
||||
|
||||
cout << "PEA Projekt 2 v2.0ALPHA Plus" << endl;
|
||||
cout << "Jan Potocki 2017-2019" << endl;
|
||||
cout << "(beerware)" << endl;
|
||||
if(useListGraph)
|
||||
cout << "Uzycie listowej reprezentacji grafu" << endl;
|
||||
else
|
||||
cout << "Uzycie macierzowej reprezentacji grafu" << endl;
|
||||
cout << endl;
|
||||
|
||||
int salesmanSelection;
|
||||
do
|
||||
{
|
||||
cout << "1 - wygeneruj losowe dane" << endl;
|
||||
cout << "2 - wyswietl dane" << endl;
|
||||
cout << "3 - dywersyfikacja TS" << endl;
|
||||
cout << "4 - czas zatrzymania TS" << endl;
|
||||
cout << "5 - tabu search" << endl;
|
||||
cout << "6 - algorytm zachlanny" << endl;
|
||||
cout << "7 - podzial i ograniczenia" << endl;
|
||||
cout << "8 - przeglad zupelny" << endl;
|
||||
cout << "9 - automatyczne pomiary (tabu search)" << endl;
|
||||
cout << "10 - wczytaj dane z pliku ATSP" << endl;
|
||||
cout << "11 - wczytaj dane z pliku TSP" << endl;
|
||||
cout << "Aby zakonczyc - 0" << endl;
|
||||
cout << "Wybierz: ";
|
||||
cin >> salesmanSelection;
|
||||
cout << endl;
|
||||
|
||||
switch(salesmanSelection)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
int vertex;
|
||||
cout << "Liczba miast: ";
|
||||
cin >> vertex;
|
||||
cout << endl;
|
||||
|
||||
if(graph != NULL)
|
||||
delete graph;
|
||||
|
||||
if(useListGraph)
|
||||
graph = new ListGraph(vertex);
|
||||
else
|
||||
graph = new ArrayGraph(vertex);
|
||||
|
||||
Graph::randomGenerateFullGraph(*graph, measureSalesmanDistance);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
if(graph != NULL)
|
||||
graph->displayGraph();
|
||||
else
|
||||
cout << "Brak wygenerowanych danych" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
tabuDiversification = !tabuDiversification;
|
||||
|
||||
if(tabuDiversification == true)
|
||||
cout << "Dywersyfikacja TS zostala wlaczona" << endl;
|
||||
else
|
||||
cout << "Dywersyfikacja TS zostala wylaczona" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
cout << "Poprzedni czas pracy TS: " << tabuStopTime << endl;
|
||||
cout << "Podaj nowy czas: ";
|
||||
cin >> tabuStopTime;
|
||||
cout << endl;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
if(graph != NULL)
|
||||
{
|
||||
if(tabuStopTime != 0)
|
||||
{
|
||||
cout << "Kadencja: " << tabuLength << endl;
|
||||
cout << "Czas zatrzymania algorytmu [s]: " << tabuStopTime << endl;
|
||||
|
||||
if(tabuDiversification == true)
|
||||
cout << "Dywersyfikacja wlaczona, kryterium: " << tabuIterationsToRestart << " iteracji" << endl;
|
||||
else
|
||||
cout << "Dywersyfikacja wylaczona" << endl;
|
||||
|
||||
cout << endl;
|
||||
|
||||
clock.start();
|
||||
vector<unsigned> route = Graph::travellingSalesmanTabuSearch(*graph, tabuLength, tabuDiversification, tabuIterationsToRestart, tabuStopTime, tabuThreadsNumber);
|
||||
clock.stop();
|
||||
|
||||
// Wyswietlenie trasy
|
||||
unsigned distFromStart = 0;
|
||||
unsigned length = 0;
|
||||
cout << route.at(0) << '\t' << length << '\t' << distFromStart << endl;
|
||||
for(int i = 1; i < route.size(); i++)
|
||||
{
|
||||
length = graph->getWeight(route.at(i - 1), route.at(i));
|
||||
distFromStart += length;
|
||||
|
||||
cout << route.at(i) << '\t' << length << '\t' << distFromStart << endl;
|
||||
}
|
||||
|
||||
cout << "Dlugosc trasy: " << distFromStart << endl;
|
||||
cout << endl;
|
||||
cout << "Czas wykonania algorytmu [s]: " << clock.read() << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Easter egg ;-)
|
||||
cout << "+++ MELON MELON MELON +++ Blad: Brak Sera! +++ !!!!! +++" << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
cout << "+++ MELON MELON MELON +++ Brak zaladowanych danych +++" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
if(graph != NULL)
|
||||
{
|
||||
clock.start();
|
||||
vector<unsigned> route = Graph::travellingSalesmanGreedy(*graph, 0);
|
||||
clock.stop();
|
||||
|
||||
// Wyswietlenie trasy
|
||||
unsigned distFromStart = 0;
|
||||
unsigned length = 0;
|
||||
cout << route.at(0) << '\t' << length << '\t' << distFromStart << endl;
|
||||
for(int i = 1; i < route.size(); i++)
|
||||
{
|
||||
length = graph->getWeight(route.at(i - 1), route.at(i));
|
||||
distFromStart += length;
|
||||
|
||||
cout << route.at(i) << '\t' << length << '\t' << distFromStart << endl;
|
||||
}
|
||||
|
||||
cout << "Dlugosc trasy: " << distFromStart << endl;
|
||||
cout << endl;
|
||||
cout << "Czas wykonania algorytmu [s]: " << clock.read() << endl;
|
||||
}
|
||||
else
|
||||
cout << "+++ MELON MELON MELON +++ Brak zaladowanych danych +++" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
{
|
||||
if(graph != NULL)
|
||||
{
|
||||
clock.start();
|
||||
vector<unsigned> route = Graph::travellingSalesmanBranchAndBound(*graph);
|
||||
clock.stop();
|
||||
|
||||
// Wyswietlenie trasy
|
||||
unsigned distFromStart = 0;
|
||||
unsigned length = 0;
|
||||
cout << route.at(0) << '\t' << length << '\t' << distFromStart << endl;
|
||||
for(int i = 1; i < route.size(); i++)
|
||||
{
|
||||
length = graph->getWeight(route.at(i - 1), route.at(i));
|
||||
distFromStart += length;
|
||||
|
||||
cout << route.at(i) << '\t' << length << '\t' << distFromStart << endl;
|
||||
}
|
||||
|
||||
cout << "Dlugosc trasy: " << distFromStart << endl;
|
||||
cout << endl;
|
||||
cout << "Czas wykonania algorytmu [s]: " << clock.read() << endl;
|
||||
}
|
||||
else
|
||||
cout << "+++ MELON MELON MELON +++ Brak zaladowanych danych +++" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
{
|
||||
if(graph != NULL)
|
||||
{
|
||||
clock.start();
|
||||
vector<unsigned> route = Graph::travellingSalesmanBruteForce(*graph);
|
||||
clock.stop();
|
||||
|
||||
// Wyswietlenie trasy
|
||||
unsigned distFromStart = 0;
|
||||
unsigned length = 0;
|
||||
cout << route.at(0) << '\t' << length << '\t' << distFromStart << endl;
|
||||
for(int i = 1; i < route.size(); i++)
|
||||
{
|
||||
length = graph->getWeight(route.at(i - 1), route.at(i));
|
||||
distFromStart += length;
|
||||
|
||||
cout << route.at(i) << '\t' << length << '\t' << distFromStart << endl;
|
||||
}
|
||||
|
||||
cout << "Dlugosc trasy: " << distFromStart << endl;
|
||||
cout << endl;
|
||||
cout << "Czas wykonania algorytmu [s]: " << clock.read() << endl;
|
||||
}
|
||||
else
|
||||
cout << "+++ MELON MELON MELON +++ Brak zaladowanych danych +++" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
{
|
||||
// PEA 2
|
||||
// Jan Potocki 2017
|
||||
if(graph != NULL)
|
||||
{
|
||||
double measureResults[measureNumber], measureResultsDiv[measureNumber];
|
||||
for(int i = 0; i < measureNumber; i++)
|
||||
{
|
||||
measureResults[i] = 0;
|
||||
measureResultsDiv[i] = 0;
|
||||
}
|
||||
|
||||
cout << "Pomiary dla problemu komiwojazera, tabu search" << tabuLength << endl;
|
||||
cout << "Kadencja: " << tabuLength << endl;
|
||||
cout << "Kryterium dywersyfikacji: " << tabuIterationsToRestart << " iteracji" << endl;
|
||||
|
||||
// Petla pomiarowa
|
||||
for(int krok = 0; krok < measureIterations; krok++)
|
||||
{
|
||||
for(int i = 0; i < measureNumber; i++)
|
||||
{
|
||||
vector<unsigned> route;
|
||||
unsigned routeLength;
|
||||
|
||||
// Bez dywersyfikacji
|
||||
cout << "Pomiar " << measureTabuStop[i] << " [s] (" << krok + 1 << " z " << measureIterations << " bez dywersyfikacji)..." << endl;
|
||||
|
||||
route = Graph::travellingSalesmanTabuSearch(*graph, tabuLength, false, tabuIterationsToRestart, measureTabuStop[i], tabuThreadsNumber);
|
||||
|
||||
routeLength = 0;
|
||||
for(int j = 1; j < route.size(); j++)
|
||||
routeLength += graph->getWeight(route.at(j - 1), route.at(j));
|
||||
measureResults[i] += routeLength;
|
||||
|
||||
// Z dywersyfikacja
|
||||
cout << "Pomiar " << measureTabuStop[i] << " [s] (" << krok + 1 << " z " << measureIterations << " z dywersyfikacja)..." << endl;
|
||||
|
||||
route = Graph::travellingSalesmanTabuSearch(*graph, tabuLength, true, tabuIterationsToRestart, measureTabuStop[i], tabuThreadsNumber);
|
||||
|
||||
routeLength = 0;
|
||||
for(int j = 1; j < route.size(); j++)
|
||||
routeLength += graph->getWeight(route.at(j - 1), route.at(j));
|
||||
measureResultsDiv[i] += routeLength;
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Opracowywanie wynikow..." << endl;
|
||||
|
||||
for(int i = 0; i < measureNumber; i++)
|
||||
{
|
||||
measureResults[i] = nearbyint(measureResults[i] / measureIterations);
|
||||
measureResultsDiv[i] = nearbyint(measureResultsDiv[i] / measureIterations);
|
||||
}
|
||||
|
||||
cout << "Zapis wynikow..." << endl;
|
||||
|
||||
ofstream salesmanToFile;
|
||||
salesmanToFile.open("wyniki-komiwojazer-ts.txt");
|
||||
salesmanToFile << "czas - bez dywersyfikacji - z dywersyfikacja" << endl;
|
||||
for(int i = 0; i < measureNumber; i++)
|
||||
{
|
||||
salesmanToFile << measureTabuStop[i] << " [s]: " << (int)measureResults[i] << ' ' << (int)measureResultsDiv[i] << endl;
|
||||
}
|
||||
salesmanToFile.close();
|
||||
|
||||
cout << "Gotowe!" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "+++ MELON MELON MELON +++ Brak zaladowanych danych +++" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
{
|
||||
// Jan Potocki 2017
|
||||
string filename, fileInput;
|
||||
ifstream salesmanDataFile;
|
||||
|
||||
cout << "Podaj nazwe pliku: ";
|
||||
cin >> filename;
|
||||
|
||||
salesmanDataFile.open(filename.c_str());
|
||||
if(salesmanDataFile.is_open())
|
||||
{
|
||||
do
|
||||
salesmanDataFile >> fileInput;
|
||||
while(fileInput != "DIMENSION:");
|
||||
|
||||
salesmanDataFile >> fileInput;
|
||||
int vertex = stoi(fileInput);
|
||||
|
||||
do
|
||||
salesmanDataFile >> fileInput;
|
||||
while(fileInput != "EDGE_WEIGHT_FORMAT:");
|
||||
|
||||
salesmanDataFile >> fileInput;
|
||||
if(fileInput == "FULL_MATRIX")
|
||||
{
|
||||
if(graph != NULL)
|
||||
delete graph;
|
||||
|
||||
if(useListGraph)
|
||||
graph = new ListGraph(vertex);
|
||||
else
|
||||
graph = new ArrayGraph(vertex);
|
||||
|
||||
do
|
||||
salesmanDataFile >> fileInput;
|
||||
while(fileInput != "EDGE_WEIGHT_SECTION");
|
||||
|
||||
for(int i = 0; i < vertex; i++)
|
||||
{
|
||||
for(int j = 0; j < vertex; j++)
|
||||
{
|
||||
salesmanDataFile >> fileInput;
|
||||
int weight = stoi(fileInput);
|
||||
|
||||
if(i != j)
|
||||
graph->addEdge(i, j, weight);
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Wczytano - liczba wierzcholkow: " << vertex << endl;
|
||||
cout << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "+++ MELON MELON MELON +++ Nieobslugiwany format " << fileInput << " +++" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
salesmanDataFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "+++ MELON MELON MELON +++ Brak pliku " << filename << " +++" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
{
|
||||
// Jan Potocki 2017
|
||||
string filename, fileInput;
|
||||
vector<float> xCoord, yCoord;
|
||||
ifstream salesmanDataFile;
|
||||
|
||||
cout << "Podaj nazwe pliku: ";
|
||||
cin >> filename;
|
||||
|
||||
salesmanDataFile.open(filename.c_str());
|
||||
if(salesmanDataFile.is_open())
|
||||
{
|
||||
do
|
||||
salesmanDataFile >> fileInput;
|
||||
while(fileInput != "DIMENSION:");
|
||||
|
||||
salesmanDataFile >> fileInput;
|
||||
int vertex = stoi(fileInput);
|
||||
|
||||
do
|
||||
salesmanDataFile >> fileInput;
|
||||
while(fileInput != "EDGE_WEIGHT_TYPE:");
|
||||
|
||||
salesmanDataFile >> fileInput;
|
||||
if(fileInput == "EUC_2D")
|
||||
{
|
||||
if(graph != NULL)
|
||||
delete graph;
|
||||
|
||||
if(useListGraph)
|
||||
graph = new ListGraph(vertex);
|
||||
else
|
||||
graph = new ArrayGraph(vertex);
|
||||
|
||||
do
|
||||
salesmanDataFile >> fileInput;
|
||||
while(fileInput != "NODE_COORD_SECTION");
|
||||
|
||||
for(int i = 0; i < vertex; i++)
|
||||
{
|
||||
salesmanDataFile >> fileInput;
|
||||
|
||||
salesmanDataFile >> fileInput;
|
||||
xCoord.push_back(stof(fileInput));
|
||||
|
||||
salesmanDataFile >> fileInput;
|
||||
yCoord.push_back(stof(fileInput));
|
||||
}
|
||||
|
||||
// To daloby sie zrobic optymalniej (macierz symetryczna), ale nie chce mi sie ...
|
||||
// ..wole zoptymalizować czas programowania ;-)
|
||||
for(int i = 0; i < vertex; i++)
|
||||
{
|
||||
for(int j = 0; j < vertex; j++)
|
||||
{
|
||||
if(i != j)
|
||||
{
|
||||
float xDiff = xCoord.at(i) - xCoord.at(j);
|
||||
float yDiff = yCoord.at(i) - yCoord.at(j);
|
||||
int weight = nearbyint(sqrt(xDiff * xDiff + yDiff * yDiff));
|
||||
|
||||
graph->addEdge(i, j, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Wczytano - liczba wierzcholkow: " << vertex << endl;
|
||||
cout << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "+++ MELON MELON MELON +++ Nieobslugiwany format " << fileInput << " +++" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
salesmanDataFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "+++ MELON MELON MELON +++ Brak pliku " << filename << " +++" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
{
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
cout << "Nieprawidlowy wybor" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
} while(salesmanSelection != 0);
|
||||
|
||||
if(graph != NULL)
|
||||
delete graph;
|
||||
|
||||
cout << "Konczenie..." << endl;
|
||||
// Easter egg :-P
|
||||
cout << '"' << "Myslak Stibbons niepokoil sie HEX-em." << endl;
|
||||
cout << "Nie wiedzial, jak dziala, chociaz wszyscy uwazali, ze wie." << endl;
|
||||
cout << "Oczywiscie, calkiem niezle orientowal sie w niektorych elementach;" << endl;
|
||||
cout << "byl tez pewien, ze HEX mysli o problemach, przeksztalcajac je" << endl;
|
||||
cout << "w liczby i mielac ..." << '"' << endl;
|
||||
cout << "(Terry Pratchett, " << '"' << "Wiedzmikolaj" << '"' << ", tlumaczenie Piotr Cholewa)" << endl;
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user