public override int[] GetPath(int n, IMeasure measure)
        {
            var baseState = new GenerationState
                {
                    C = new double[n,n],
                    Edges = new List<Edge>(n),
                    N = n,
                    VertexSet = new int[n]
                };
            baseState.C = measure.GetMatrix();
            for (int i = 0; i < n; i++)
            {
                baseState.C[i, i] = Inf;
            }
            baseState.J = ReductMatrix(n, baseState.C);
            for (int i = 0; i < n; i++)
            {
                baseState.VertexSet[i] = i;
            }

            var queue = new PriorityQueue<GenerationState>((a, b) => -a.J.CompareTo(b.J));
            queue.Enqueue(baseState);

            while (queue.Count > 0)
            {
                var current = queue.Dequeue();

                if (current.Edges.Count == n - 1)
                {
                    var result = GetResult(n, current.Edges);
                    return result;
                }

                Process(current, queue);
            }

            throw new ApplicationException("Path not found");
        }
        private void Process(GenerationState state, PriorityQueue<GenerationState> queue)
        {
            //state.J = ReductMatrix(state.N, state.C);

            int bestI = 0, bestJ = 0;
            double bestMax = -1;
            int n = state.N;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (state.C[i, j] < Eps)
                    {
                        double m = GetMinSum(n, state.C, i, j);
                        if (bestMax < m)
                        {
                            bestMax = m;
                            bestI = i;
                            bestJ = j;
                        }
                    }
                }
            }

            if (state.C[bestI, bestJ] > InfBound)
            {
                return;
            }

            // get state 1
            var stateWithoutEdge = new GenerationState
                {
                    N = state.N,
                    C = new double[n,n],
                    Edges = state.Edges,
                    VertexSet = state.VertexSet
                };
            Array.Copy(state.C, stateWithoutEdge.C, state.C.Length);
            stateWithoutEdge.C[bestI, bestJ] = Inf; // TODO: Remove j -> i ??
            double r2 = ReductMatrix(n, stateWithoutEdge.C);
            stateWithoutEdge.J = state.J + r2;

            // get state 2
            var stateWithEdge = new GenerationState
            {
                N = state.N,
                C = new double[n, n],
                Edges = new List<Edge>(state.Edges),
                VertexSet = new int[n]
            };

            Array.Copy(state.C, stateWithEdge.C, state.C.Length);
            for (int i = 0; i < n; i++)
            {
                stateWithEdge.C[i, bestJ] = Inf;
            }
            for (int j = 0; j < n; j++)
            {
                stateWithEdge.C[bestI, j] = Inf;
            }
            stateWithEdge.C[bestJ, bestI] = Inf;

            Array.Copy(state.VertexSet, stateWithEdge.VertexSet, n);
            int c1 = stateWithEdge.VertexSet[bestI];
            int c2 = stateWithEdge.VertexSet[bestJ];
            for (int i = 0; i < n; i++)
            {
                if (stateWithEdge.VertexSet[i] == c1)
                {
                    for (int j = 0; j < n; j++)
                    {
                        if (stateWithEdge.VertexSet[j] == c2)
                        {
                            stateWithEdge.C[i, j] = Inf;
                            stateWithEdge.C[j, i] = Inf;
                        }
                    }
                }
            }
            for (int i = 0; i < n; i++)
            {
                if (stateWithEdge.VertexSet[i] == c2)
                {
                    stateWithEdge.VertexSet[i] = c1;
                }
            }

            double r1 = ReductMatrix(n, stateWithEdge.C);
            stateWithEdge.J = state.J + r1;
            stateWithEdge.Edges.Add(new Edge(bestI, bestJ));

            queue.Enqueue(stateWithEdge);
            queue.Enqueue(stateWithoutEdge);

            return;
        }