public RAlgorithSolver(int n, List<MarkedPointD> discreteSet, List<MarkedPointD> initialSet)
        {
            this.k = n;
            this.c = n;

            DiscreteSet = new DiscreteSet(discreteSet, initialSet);

            x = new double[n];

            Random r = new Random();

            for (int i = 0; i < n / 2; i++)
            {
                x[i] = initialSet[i].X;
                x[i + n / 2] = initialSet[i].Y;
            }
        }
        public static List<MarkedPointD> FindOptimalAllocation(
            List<MarkedPointD> discreteSet,
            List<MarkedPointD> initialSourceSet,
            double discretizationStep,
            double sourceMovingStep,
            double stepDecreasingMultiplier,
            double stepMinimum,
            double eps
            )
        {
            DiscreteSet = new DiscreteSet(discreteSet, initialSourceSet);
            OptimalSourceSet = new List<MarkedPointD>();
            foreach (var source in initialSourceSet)
            {
                var point = new MarkedPointD(source.X, source.Y);
                OptimalSourceSet.Add(point);
            }
            DiscretizationStep = discretizationStep;
            SourceMovingStep = sourceMovingStep;
            StepDecreasingMultiplier = stepDecreasingMultiplier;
            StepMinimum = stepMinimum;
            Eps = eps;
            while (true)
            {
                //1 step
                DiscreteSet.SetFieldValue(); //Расчитываем D в узлах сетки
                LocalMinimumSet = DiscreteSet.FindLocalMinimums(DiscretizationStep);
                globalMinimum = DiscreteSet.MinimumFieldValue;
                //globalMinimum = LocalMinimumSet.Select(point => point.FieldValue).Min();
                GlobalMinimumSet = LocalMinimumSet.FindAll(minimum => Math.Abs(minimum.FieldValue - globalMinimum) < Eps);
                if (LocalMinimumSet.Count == GlobalMinimumSet.Count)
                    break; //Go to step 6

                if (globalMinimum < Mu)
                {
                    SourceMovingStep = SourceMovingStep * StepDecreasingMultiplier;
                    if (SourceMovingStep < StepMinimum)
                        break; //Go to step 6
                }
                else
                {
                    Mu = globalMinimum;

                    OptimalSourceSet = new List<MarkedPointD>();
                    foreach (var source in DiscreteSet.SourceSet)
                    {
                        var point = new MarkedPointD(source.X, source.Y);
                        OptimalSourceSet.Add(point);
                    }
                }

                //Step 4
                foreach (var source in DiscreteSet.SourceSet)
                {
                    var min = GlobalMinimumSet.FirstOrDefault(m => m.GetDistanceToPoint(source) == GlobalMinimumSet.Select(p => p.GetDistanceToPoint(source)).Min());
                    var distance = source.GetDistanceToPoint(min);
                    if (SourceMovingStep < distance)
                    {
                        double k = SourceMovingStep / distance;
                        source.X = (source.X + k * min.X) / (1 + k);
                        source.Y = (source.Y + k * min.Y) / (1 + k);
                    }
                    else
                    {
                        double k = distance / SourceMovingStep;
                        source.X = ((1 + k) * min.X - source.X) / k;
                        source.Y = ((1 + k) * min.Y - source.Y) / k;
                    }

                    var nearestPoint = DiscreteSet.Set.FirstOrDefault(s => s.GetDistanceToPoint(source) == DiscreteSet.Set.Select(p => p.GetDistanceToPoint(source)).Min());
                    source.X = nearestPoint.X;
                    source.Y = nearestPoint.Y;
                }

            }
            return OptimalSourceSet;
        }