/// <summary>
        /// Metoda generująca kandydatów tras
        /// </summary>
        /// <returns></returns>
        private List<Route> generateCandidates()
        {
            var tmpCandidates = new List<Route>();
            var actualRoutePoints = ActualSolution.Points;
            int r1,r2;
            while (tmpCandidates.Count < NumberOfGeneratedCandidates)
            {
                //Losowanie pary miast
                var tmpPointArray = new int[actualRoutePoints.Length];
                actualRoutePoints.CopyTo(tmpPointArray, 0);

                r1 = random.Next(0, actualRoutePoints.Length);
                do{
                    r2 = random.Next(0, actualRoutePoints.Length);
                } while (r1 == r2);

                //zamiana miast w tablicy trasy
                int temp = tmpPointArray[r1];
                tmpPointArray[r1] = tmpPointArray[r2];
                tmpPointArray[r2] = temp;

                Route tmpRoute = null;
                if (r1 > r2)
                {
                    tmpRoute = new Route { Points = tmpPointArray, ChangedIndex1 = r1, ChangedIndex2 = r2 };
                }
                else
                {
                    tmpRoute = new Route { Points = tmpPointArray, ChangedIndex1 = r2, ChangedIndex2 = r1 };
                }

                // jeśli w liście kandydatów nie ma takiej pary zamienionych miast to dodaj ją do listy i oblicz jej koszt
                if (!tmpCandidates.Any(i => i.ChangedIndex1 == tmpRoute.ChangedIndex1 && i.ChangedIndex2 == tmpRoute.ChangedIndex2))
                {
                    CalculateCost(tmpRoute);
                    tmpCandidates.Add(tmpRoute);
                }

            }
            return tmpCandidates;
        }
        /// <summary>
        /// metoda generuje losową trasę jako początek algorytmu
        /// </summary>
        /// <returns>obiekt trasy</returns>
        private Route GenerateRandomRoute()
        {
            var tmpRoute = new Route();
            var k = DistanceArray.GetLength(0);
            tmpRoute.Points = new int[k];

            // wypełniam tablicę kolejnymi liczbami od 0
            for (int i = 0; i < tmpRoute.Points.Length; i++)
            {
                tmpRoute.Points[i] = i;
            }
            for (int i = 0; i < tmpRoute.Points.Length; i++)
            {
                int randomIndex = random.Next(0, k - 1);
                int temp = tmpRoute.Points[randomIndex];
                tmpRoute.Points[randomIndex] = tmpRoute.Points[k - 1];
                tmpRoute.Points[k - 1] = temp;
                k--;
            }
            return tmpRoute;
        }
        /// <summary>
        /// Metoda obliczająca koszt trasy
        /// </summary>
        /// <param name="route">obiekt trasy</param>
        private void CalculateCost(Route route)
        {
            for (int i = 0; i < route.Points.Length - 1; i++)
            {
                route.Cost += DistanceArray[route.Points[i], route.Points[i + 1]];
            }
            // powrót do punktu startowego
            route.Cost += DistanceArray[route.Points[route.Points.Length - 1], route.Points[0]];

            // wyliczanie kosztu z uwzględnieniem częstotliwości
            route.TabuAdjustedCost = route.Cost;
            route.TabuAdjustedCost = Convert.ToInt32(route.TabuAdjustedCost - (FrequencyAdjustment * TabuArray[route.ChangedIndex2, route.ChangedIndex1]));
        }