protected static void ApplyTsp(VrpData data, VrpResult result)
        {
            var tspSolver = new Opt2();
            for (int i = 0; i < data.V; i++)
            {
                var route = result.Routes[i];
                if (route.Count > 4)
                {
                    route.RemoveAt(route.Count - 1);
                    var measure =
                        new MatrixMeasureFactory().CreateMatrixMeasure(route.Select(x => data.Customers[x].Point).ToArray());
                    var tspRoute = tspSolver.GetPath(route.Count, measure);

                    int startIndex = 0;
                    for (int j = 0; j < tspRoute.Length; j++)
                    {
                        if (tspRoute[j] == 0)
                        {
                            startIndex = j;
                            break;
                        }
                    }
                    result.Routes[i] = new List<int>();
                    for (int j = startIndex; j < tspRoute.Length; j++)
                    {
                        result.Routes[i].Add(route[tspRoute[j]]);
                    }
                    for (int j = 0; j < startIndex; j++)
                    {
                        result.Routes[i].Add(route[tspRoute[j]]);
                    }
                    result.Routes[i].Add(0);
                }
                else
                {
                    result.Routes[i] = route;
                }
            }
        }
        private static void SquareTest()
        {
            int n = 8;
            double[,] m = new double[n,n];
            /*for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    m[i, j] = 1;
                }
            }*/

            var points = new List<Point2DReal>
                {
                    new Point2DReal(0, 0),
                    new Point2DReal(2, 2),
                    new Point2DReal(2, 0),
                    new Point2DReal(0, 2),
                    new Point2DReal(1, 2),
                    new Point2DReal(0, 1),
                    new Point2DReal(1, 0),
                    new Point2DReal(2, 1),
                };

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    m[i, j] = points[i].Dist(points[j]);
                }
            }

            try
            {
                var algorithm = new LittleAlgorithm();
                var measure = new MatrixMeasureFactory().CreateMatrixMeasure(points);
                var path = algorithm.GetPath(n, measure);
                for (int i = 0; i < n; i++)
                {
                    Console.Write("{0} ", path[i]);
                }
                Console.WriteLine();
                for (int i = 0; i < n; i++)
                {
                    Console.WriteLine("{0} {1}", points[path[i]].X, points[path[i]].Y);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
        public static void Main(string[] args)
        {
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

            //var lines = args[0].Split('\n');
            string text;
            using (var reader = File.OpenText(args[0]))
            {
                text = reader.ReadToEnd();
            }
            var lines = text.Split('\n');

            var n = int.Parse(lines[0]);
            var points = new Point2DReal[n];
            for (int i = 0; i < n; i++)
            {
                var line = lines[i + 1].Split();
                var x = double.Parse(line[0]);
                var y = double.Parse(line[1]);
                points[i] = new Point2DReal(x, y);
            }
            /*var matrix = new double[n,n];
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    matrix[i, j] = points[i].Dist(points[j]);
                }
            }

            double avgDist = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    avgDist += matrix[i, j];
                }
            }
            avgDist /= (n * n);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    matrix[i, j] /= avgDist;
                }
            }*/

            IMeasure measure;
            if (n <= 6000)
            {
                measure = new MatrixMeasureFactory().CreateMatrixMeasure(points);
            }
            else
            {
                measure = new PointsMeasure(points);
            }

            var path = new Opt3().GetPath(n, measure);

            var ans = points[path[0]].Dist(points[path[n - 1]]);
            for (int i = 0; i < n - 1; i++)
            {
                ans += points[path[i]].Dist(points[path[i + 1]]);
            }

            Console.WriteLine("{0} 0", ans);
            Console.WriteLine(string.Join(" ", path));
        }