Implementacja tabu search dla TSP
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

Graph.cpp 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. #include "Graph.h"
  2. #include "Stopwatch.h"
  3. #include <algorithm>
  4. #include <chrono>
  5. #include <queue>
  6. #include <random>
  7. #include <thread>
  8. #include <iostream>
  9. Graph::Graph()
  10. {
  11. //ctor
  12. }
  13. Graph::~Graph()
  14. {
  15. //dtor
  16. }
  17. unsigned Graph::getVertexNumber()
  18. {
  19. return vertexNumber;
  20. }
  21. void Graph::randomGenerateFullGraph(Graph &graph, unsigned maxWeight)
  22. {
  23. std::random_device randomSrc;
  24. std::default_random_engine randomGen(randomSrc());
  25. std::uniform_int_distribution<> weightDist(1, maxWeight);
  26. for(int i = 0; i < graph.vertexNumber; i++)
  27. {
  28. for(int j = 0; j < graph.vertexNumber; j++)
  29. {
  30. if(i != j)
  31. {
  32. // Bez warunku na krawedzie juz wygenerowane...
  33. // ...z tym radzi sobie juz metoda addEdge
  34. int randomWeight = weightDist(randomGen);
  35. graph.addEdge(i, j, randomWeight);
  36. }
  37. }
  38. }
  39. }
  40. std::vector<unsigned> Graph::travellingSalesmanBruteForce(Graph &graph)
  41. {
  42. // ALGORYTM przegladu zupelnego
  43. // Implementacja: Jan Potocki 2017
  44. // (refactoring 2019)
  45. std::vector<unsigned> vertexArray;
  46. // Generowanie "spisu" wierzcholkow
  47. // (od razu w odpowiedniej kolejnosci dla next_permutation)
  48. for(int i = 1; i < graph.vertexNumber; i++)
  49. vertexArray.push_back(i);
  50. std::vector<unsigned> minCombination;
  51. int minRoute = -1;
  52. // Petla przegladajaca kolejne permutacje
  53. do
  54. {
  55. std::vector<unsigned> combination;
  56. // Dodanie wierzcholka startowego i pierwszego na trasie
  57. combination.push_back(0);
  58. combination.push_back(vertexArray.front());
  59. // W petli reszta wiercholkow
  60. for(int i = 1; i < vertexArray.size(); i++)
  61. combination.push_back(vertexArray.at(i));
  62. // Powrot do wierzcholka startowego
  63. combination.push_back(0);
  64. // PEA 2
  65. // Jan Potocki 2017
  66. int route = 0;
  67. for(int i = 1; i < combination.size(); i++)
  68. route += graph.getWeight(combination.at(i - 1), combination.at(i));
  69. if(minRoute == -1 || route < minRoute)
  70. {
  71. minRoute = route;
  72. minCombination = combination;
  73. }
  74. }
  75. while(next_permutation(vertexArray.begin(), vertexArray.end()));
  76. return minCombination;
  77. }
  78. std::vector<unsigned> Graph::travellingSalesmanBranchAndBound(Graph &graph)
  79. {
  80. // ALGORYTM pracujacy w oparciu o kolejke priorytetowa i niejawnie utworzone drzewo
  81. // Zrodlo: www.ii.uni.wroc.pl/~prz/2011lato/ah/opracowania/met_podz_ogr.opr.pdf
  82. // Autor: Mateusz Lyczek 2011
  83. // Implementacja: Jan Potocki 2017
  84. std::priority_queue<std::vector<unsigned>, std::vector< std::vector<unsigned> >, RouteComparison> routeQueue;
  85. std::vector<unsigned> optimalRoute; // Tu bedziemy zapisywac optymalne (w danej chwili) rozwiazanie
  86. int optimalRouteLength = -1; // -1 - bedziemy odtad uznawac, ze to jest nieskonczonosc ;-)
  87. // UMOWA
  88. // Pierwszy element wektora to dlugosc trasy (trzeba ustawic "z palca"!)
  89. // Kolejne to wierzcholki na trasie
  90. std::vector<unsigned> currentRoute; // Niejawne tworzenie drzewa, tu bedzie korzen
  91. currentRoute.push_back(0); // Poczatkowe oszacowanie nie ma znaczenia
  92. currentRoute.push_back(0); // Wierzcholek startowy (korzen drzewa rozwiazan)
  93. routeQueue.push(currentRoute); // Dodanie do kolejki korzenia
  94. while(!routeQueue.empty())
  95. {
  96. // Przypisanie korzenia do dalszej roboty
  97. currentRoute = routeQueue.top();
  98. routeQueue.pop();
  99. // Sprawdzenie, czy rozwiazanie jest warte rozwijania, czy odrzucic
  100. if(optimalRouteLength == -1 || currentRoute.at(0) < optimalRouteLength)
  101. {
  102. for(int i = 0; i < graph.vertexNumber; i++)
  103. {
  104. // Petla wykonywana dla kazdego potomka rozpatrywanego wlasnie rozwiazania w drzewie
  105. // Ustalenie, czy dany wierzcholek mozna jeszcze wykorzystac, czy juz zostal uzyty
  106. bool vertexUsed = false;
  107. for(int j = 1; j < currentRoute.size(); j++)
  108. {
  109. if(currentRoute.at(j) == i)
  110. {
  111. vertexUsed = true;
  112. break;
  113. }
  114. }
  115. if(vertexUsed)
  116. continue;
  117. // Niejawne utworzenie nowego wezla reprezuntujacego rozpatrywane rozwiazanie...
  118. std::vector<unsigned> nextRoute = currentRoute;
  119. //unsigned nextLength = graph.getWeight(nextRoute.back(), i);
  120. nextRoute.push_back(i);
  121. // Dalej bedziemy postepowac roznie...
  122. if(nextRoute.size() > graph.vertexNumber)
  123. {
  124. // Doszlismy wlasnie do liscia
  125. // Dodajemy droge powrotna, nie musimy nic szacowac
  126. // (wszystko juz wiemy)
  127. nextRoute.push_back(0);
  128. nextRoute.at(0) = 0;
  129. for(int j = 1; j < nextRoute.size() - 1; j++)
  130. {
  131. // Liczymy dystans od poczatku do konca
  132. nextRoute.at(0) += graph.getWeight(nextRoute.at(j), nextRoute.at(j+ 1));
  133. }
  134. if(optimalRouteLength == -1 || nextRoute.at(0) < optimalRouteLength)
  135. {
  136. optimalRouteLength = nextRoute.at(0);
  137. nextRoute.erase(nextRoute.begin());
  138. optimalRoute = nextRoute;
  139. }
  140. }
  141. else
  142. {
  143. // Liczenie tego, co juz wiemy, od nowa...
  144. // (dystans od poczatku)
  145. nextRoute.at(0) = 0;
  146. for(int j = 1; j < nextRoute.size() - 1; j++)
  147. {
  148. nextRoute.at(0) += graph.getWeight(nextRoute.at(j), nextRoute.at(j + 1));
  149. }
  150. // Reszte szacujemy...
  151. // Pomijamy od razu wierzcholek startowy
  152. for(int j = 1; j < graph.vertexNumber; j++)
  153. {
  154. // Odrzucenie wierzcholkow juz umieszczonych na trasie
  155. bool vertexUsed = false;
  156. for(int k = 1; k < currentRoute.size(); k++)
  157. {
  158. if(j == currentRoute.at(k))
  159. {
  160. vertexUsed = true;
  161. break;
  162. }
  163. }
  164. if(vertexUsed)
  165. continue;
  166. int minEdge = -1;
  167. for(int k = 0; k < graph.vertexNumber; k++)
  168. {
  169. // Odrzucenie krawedzi do wierzcholka 0 przy ostatnim wierzcholku w czesciowym rozwiazaniu
  170. // Wyjatkiem jest ostatnia mozliwa krawedz
  171. if(j == i && k == 0)
  172. continue;
  173. // Odrzucenie krawedzi do wierzcholka umieszczonego juz na rozwazanej trasie
  174. bool vertexUsed = false;
  175. for(int l = 2; l < nextRoute.size(); l++)
  176. {
  177. if(k == nextRoute.at(l))
  178. {
  179. vertexUsed = true;
  180. break;
  181. }
  182. }
  183. if(vertexUsed)
  184. continue;
  185. // Odrzucenie samego siebie
  186. if(k == j)
  187. continue;
  188. // Znalezienie najkrotszej mozliwej jeszcze do uzycia krawedzi
  189. unsigned consideredLength = graph.getWeight(j, k);
  190. if(minEdge == -1)
  191. minEdge = consideredLength;
  192. else if(minEdge > consideredLength)
  193. minEdge = consideredLength;
  194. }
  195. nextRoute.at(0) += minEdge;
  196. }
  197. // ...i teraz zastanawiamy sie co dalej
  198. if(optimalRouteLength == -1 || nextRoute.at(0) < optimalRouteLength)
  199. {
  200. routeQueue.push(nextRoute);
  201. }
  202. }
  203. }
  204. }
  205. else
  206. {
  207. // Jezeli jedno rozwiazanie odrzucilismy, to wszystkie inne tez mozemy
  208. // (kolejka priorytetowa, inne nie moga byc lepsze)
  209. break;
  210. }
  211. }
  212. return optimalRoute;
  213. }
  214. std::vector<unsigned> Graph::travellingSalesmanGreedy(Graph &graph, unsigned startVertex)
  215. {
  216. // ALGORYTM zachlanny z wierzcholkiem startowym przekazanym w parametrze
  217. // Implementacja: Jan Potocki 2017
  218. std::vector<unsigned> route;
  219. // std::random_device randomSrc;
  220. // std::default_random_engine randomGen(randomSrc());
  221. // std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
  222. // Losowanie wierzcholka startowego
  223. //route.push_back(vertexDist(randomGen));
  224. route.push_back(startVertex);
  225. for(int i = 0; i < graph.vertexNumber - 1; i++)
  226. {
  227. int minEdge = -1;
  228. unsigned nextVertex;
  229. for(int j = 0; j < graph.vertexNumber; j++)
  230. {
  231. // Odrzucenie samego siebie lub wierzcholka startowego
  232. // (zeby bylo szybciej)
  233. if(route.back() == j || route.front() == j)
  234. continue;
  235. // Odrzucenie krawedzi do wierzcholka umieszczonego juz na trasie
  236. bool vertexUsed = false;
  237. for(int k = 0; k < route.size(); k++)
  238. {
  239. if(j == route.at(k))
  240. {
  241. vertexUsed = true;
  242. break;
  243. }
  244. }
  245. if(vertexUsed)
  246. continue;
  247. // Znalezienie najkrotszej mozliwej jeszcze do uzycia krawedzi
  248. unsigned consideredLength = graph.getWeight(route.back(), j);
  249. if(minEdge == -1)
  250. {
  251. minEdge = consideredLength;
  252. nextVertex = j;
  253. }
  254. else if(minEdge > consideredLength)
  255. {
  256. minEdge = consideredLength;
  257. nextVertex = j;
  258. }
  259. }
  260. route.push_back(nextVertex);
  261. }
  262. route.push_back(startVertex);
  263. return route;
  264. }
  265. std::vector<unsigned> Graph::travellingSalesmanHybrid(Graph &graph)
  266. {
  267. // ALGORYTM hybrydowy losowo-zachlanny
  268. // Losowa czesc wierzcholkow jest losowana, reszta zachlannie
  269. // Implementacja: Jan Potocki 2019
  270. std::vector<unsigned> route;
  271. std::random_device randomSrc;
  272. std::default_random_engine randomGen(randomSrc());
  273. std::uniform_int_distribution<> vertexNumberDist(1, graph.vertexNumber);
  274. std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
  275. // Liczba losowanych wierzcholkow
  276. unsigned randomVertexNumber = vertexNumberDist(randomGen);
  277. // Czesc losowa
  278. for(int i = 0; i < randomVertexNumber; i++)
  279. {
  280. unsigned randomVertex;
  281. bool vertexUsed;
  282. do
  283. {
  284. randomVertex = vertexDist(randomGen);
  285. vertexUsed = false;
  286. for(int j = 0; j < route.size(); j++)
  287. {
  288. if(route.at(j) == randomVertex)
  289. {
  290. vertexUsed = true;
  291. break;
  292. }
  293. }
  294. } while(vertexUsed == true);
  295. route.push_back(randomVertex);
  296. }
  297. // Czesc zachlanna
  298. for(int i = 0; i < graph.vertexNumber - randomVertexNumber; i++)
  299. {
  300. int minEdge = -1;
  301. unsigned nextVertex;
  302. for(int j = 0; j < graph.vertexNumber; j++)
  303. {
  304. // Odrzucenie samego siebie lub wierzcholka startowego
  305. // (zeby bylo szybciej)
  306. if(route.back() == j || route.front() == j)
  307. continue;
  308. // Odrzucenie krawedzi do wierzcholka umieszczonego juz na trasie
  309. bool vertexUsed = false;
  310. for(int k = 0; k < route.size(); k++)
  311. {
  312. if(j == route.at(k))
  313. {
  314. vertexUsed = true;
  315. break;
  316. }
  317. }
  318. if(vertexUsed)
  319. continue;
  320. // Znalezienie najkrotszej mozliwej jeszcze do uzycia krawedzi
  321. unsigned consideredLength = graph.getWeight(route.back(), j);
  322. if(minEdge == -1)
  323. {
  324. minEdge = consideredLength;
  325. nextVertex = j;
  326. }
  327. else if(minEdge > consideredLength)
  328. {
  329. minEdge = consideredLength;
  330. nextVertex = j;
  331. }
  332. }
  333. route.push_back(nextVertex);
  334. }
  335. route.push_back(route.front());
  336. return route;
  337. }
  338. std::vector<unsigned> Graph::travellingSalesmanRandom(Graph &graph)
  339. {
  340. // ALGORYTM losowy
  341. // Implementacja: Jan Potocki 2019
  342. std::vector<unsigned> route;
  343. std::random_device randomSrc;
  344. std::default_random_engine randomGen(randomSrc());
  345. std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
  346. for(int i = 0; i < graph.vertexNumber; i++)
  347. {
  348. unsigned randomVertex;
  349. bool vertexUsed;
  350. do
  351. {
  352. randomVertex = vertexDist(randomGen);
  353. vertexUsed = false;
  354. for(int j = 0; j < route.size(); j++)
  355. {
  356. if(route.at(j) == randomVertex)
  357. {
  358. vertexUsed = true;
  359. break;
  360. }
  361. }
  362. } while(vertexUsed == true);
  363. route.push_back(randomVertex);
  364. }
  365. route.push_back(route.front());
  366. return route;
  367. }
  368. std::vector<unsigned> Graph::travellingSalesmanTabuSearch(Graph &graph, unsigned tabuSteps, bool diversification, int iterationsToRestart, unsigned minStopTime, unsigned threadsNumber)
  369. {
  370. // ALGORYTM wielawotkowy oparty na metaheurystyce tabu search
  371. // Pomocniczy kod uruchamiajacy watki wlasciwego algorytmu w najbardziej optymalny sposob
  372. // Implementacja: Jan Potocki 2019
  373. std::vector<unsigned> startVertexVector;
  374. std::vector<std::thread> threadsVector;
  375. std::vector<std::vector<unsigned>> resultsVector(threadsNumber);
  376. std::vector<int> resultsLength(threadsNumber);
  377. std::vector<unsigned> optimalResult;
  378. int optimalResultIndex;
  379. int optimalResultLength;
  380. std::random_device randomSrc;
  381. std::default_random_engine randomGen(randomSrc());
  382. std::uniform_int_distribution<> vertexDist(0, graph.vertexNumber - 1);
  383. for(int i = 0; i < threadsNumber; i++)
  384. {
  385. std::vector<unsigned> startRoute;
  386. unsigned startVertex;
  387. bool startVertexUsed;
  388. if(i < graph.vertexNumber)
  389. {
  390. do
  391. {
  392. startVertex = vertexDist(randomGen);
  393. startVertexUsed = false;
  394. for(int j = 0; j < startVertexVector.size(); j++)
  395. {
  396. if(startVertexVector.at(j) == startVertex)
  397. {
  398. startVertexUsed = true;
  399. break;
  400. }
  401. }
  402. } while(startVertexUsed == true);
  403. startVertexVector.push_back(startVertex);
  404. startRoute = Graph::travellingSalesmanGreedy(graph, startVertex);
  405. }
  406. else
  407. {
  408. startRoute = Graph::travellingSalesmanRandom(graph);
  409. }
  410. 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))));
  411. }
  412. for(int i = 0; i < threadsNumber; i++)
  413. threadsVector.at(i).join();
  414. optimalResultIndex = 0;
  415. optimalResultLength = resultsLength.at(0);
  416. for(int i = 0; i < threadsNumber; i++)
  417. {
  418. if(resultsLength.at(i) < optimalResultLength)
  419. {
  420. optimalResultIndex = i;
  421. optimalResultLength = resultsLength.at(i);
  422. }
  423. }
  424. optimalResult = resultsVector.at(optimalResultIndex);
  425. return optimalResult;
  426. }
  427. void Graph::travellingSalesmanTabuSearchEngine(Graph &graph, unsigned tabuSteps, bool diversification, int iterationsToRestart, unsigned minStopTime, std::vector<unsigned> startRoute, std::vector<unsigned> &result, int &resultLength)
  428. {
  429. // ALGORYTM oparty na metaheurystyce tabu search z dywersyfikacja i sasiedztwem typu swap
  430. // Rdzen przeznaczony do uruchamiania jako jeden watek
  431. // Projekt i implementacja: Jan Potocki 2017
  432. // (refactoring 2019)
  433. Stopwatch onboardClock;
  434. std::vector<unsigned> optimalRoute; // Tu bedziemy zapisywac optymalne (w danej chwili) rozwiazanie
  435. int optimalRouteLength = -1; // -1 - bedziemy odtad uznawac, ze to jest nieskonczonosc ;-)
  436. std::vector<unsigned> currentRoute; // Rozpatrywane rozwiazanie
  437. // Wyznaczenie poczatkowego rozwiazania algorytmem zachlannym
  438. //currentRoute = Graph::travellingSalesmanGreedy(graph);
  439. currentRoute = startRoute;
  440. // Inicjalizacja glownej petli...
  441. std::vector< std::vector<unsigned> > tabuArray;
  442. unsigned currentTabuSteps = tabuSteps;
  443. int stopCounter = 0;
  444. bool timeNotExceeded = true;
  445. onboardClock.start();
  446. // Rdzen algorytmu
  447. while(timeNotExceeded == true)
  448. {
  449. bool cheeseSupplied = true;
  450. bool intensification = false;
  451. while(cheeseSupplied == true)
  452. {
  453. std::vector<unsigned> nextRoute;
  454. int nextRouteLength = -1;
  455. std::vector<unsigned> nextTabu(3, 0);
  456. nextTabu.at(0) = currentTabuSteps;
  457. // Generowanie sasiedztwa typu swap przez zamiane wierzcholkow
  458. // (wierzcholka startowego i zarazem ostatniego nie ruszamy,
  459. // pomijamy tez od razu aktualny wierzcholek)
  460. for(int i = 1; i < graph.vertexNumber - 1; i++)
  461. {
  462. for(int j = i + 1; j < graph.vertexNumber; j++)
  463. {
  464. std::vector<unsigned> neighbourRoute = currentRoute;
  465. // Zamiana
  466. unsigned buffer = neighbourRoute.at(j);
  467. neighbourRoute.at(j) = neighbourRoute.at(i);
  468. neighbourRoute.at(i) = buffer;
  469. unsigned neighbourRouteLength = 0;
  470. for(int i = 1; i < neighbourRoute.size(); i++)
  471. neighbourRouteLength += graph.getWeight(neighbourRoute.at(i - 1), neighbourRoute.at(i));
  472. // Sprawdzenie, czy dany ruch nie jest na liscie tabu
  473. // (dwa wierzcholki)
  474. bool tabu = false;
  475. for(int k = 0; k < tabuArray.size(); k++)
  476. {
  477. if(tabuArray.at(k).at(1) == i && tabuArray.at(k).at(2) == j)
  478. {
  479. tabu = true;
  480. break;
  481. }
  482. if(tabuArray.at(k).at(1) == j && tabuArray.at(k).at(2) == i)
  483. {
  484. tabu = true;
  485. break;
  486. }
  487. }
  488. // Kryterium aspiracji...
  489. if(tabu == true && neighbourRouteLength >= optimalRouteLength)
  490. // ...jezeli niespelnione - pomijamy ruch
  491. continue;
  492. if(nextRouteLength == -1)
  493. {
  494. nextRouteLength = neighbourRouteLength;
  495. nextRoute = neighbourRoute;
  496. nextTabu.at(1) = i;
  497. nextTabu.at(2) = j;
  498. }
  499. else if(nextRouteLength > neighbourRouteLength)
  500. {
  501. nextRouteLength = neighbourRouteLength;
  502. nextRoute = neighbourRoute;
  503. nextTabu.at(1) = i;
  504. nextTabu.at(2) = j;
  505. }
  506. }
  507. }
  508. currentRoute = nextRoute;
  509. if(optimalRouteLength == -1)
  510. {
  511. optimalRouteLength = nextRouteLength;
  512. optimalRoute = nextRoute;
  513. // Reset licznika
  514. stopCounter = 0;
  515. }
  516. else if(optimalRouteLength > nextRouteLength)
  517. {
  518. optimalRouteLength = nextRouteLength;
  519. optimalRoute = nextRoute;
  520. // Zaplanowanie intensyfikacji
  521. intensification = true;
  522. // Reset licznika
  523. stopCounter = 0;
  524. }
  525. // Weryfikacja listy tabu...
  526. // ...aktualizacja kadencji na liscie tabu
  527. for(int i = 0; i < tabuArray.size(); i++)
  528. {
  529. tabuArray.at(i).at(0)--;
  530. }
  531. //...usuniecie zerowych kadencji
  532. for(int i = 0; i < tabuArray.size(); i++)
  533. {
  534. if(tabuArray.at(i).at(0) == 0)
  535. tabuArray.erase(tabuArray.begin() + i);
  536. }
  537. // ...dopisanie ostatniego ruchu do listy tabu
  538. tabuArray.push_back(nextTabu);
  539. // Zliczenie iteracji
  540. stopCounter++;
  541. // Zmierzenie czasu
  542. onboardClock.stop();
  543. if(onboardClock.read() > minStopTime)
  544. timeNotExceeded = false;
  545. // Sprawdzenie warunku zatrzymania
  546. if(diversification == true)
  547. {
  548. // Przy aktywowanej dywersyfikacji - po zadanej liczbie iteracji bez poprawy
  549. if(stopCounter >= iterationsToRestart || timeNotExceeded == false)
  550. cheeseSupplied = false;
  551. }
  552. else
  553. {
  554. // Przy nieaktywowanej dywersyfikacji - po uplynieciu okreslonego czasu
  555. if(timeNotExceeded == false)
  556. cheeseSupplied = false;
  557. }
  558. }
  559. // Dywersyfikacja
  560. if(diversification == true)
  561. {
  562. if(intensification == true)
  563. {
  564. // Intensyfikacja przeszukiwania przy ostatnim minimum
  565. currentRoute = optimalRoute;
  566. currentTabuSteps = tabuSteps / 4;
  567. intensification = false;
  568. }
  569. else
  570. {
  571. // Algorytm hybrydowy losowo-zachlanny
  572. currentRoute = Graph::travellingSalesmanHybrid(graph);
  573. currentTabuSteps = tabuSteps;
  574. intensification = false;
  575. }
  576. }
  577. // Reset licznika iteracji przed restartem
  578. stopCounter = 0;
  579. }
  580. result = optimalRoute;
  581. resultLength = optimalRouteLength;
  582. }