Beispiel #1
0
 // creating a child node is O(n^2) for both time and space complexity
 public DistMatrix(int toNode, DistMatrix parent)
 {
     // take in the index from the parent
     this.maxIndex = parent.maxIndex;
     // add the cost of moving from the previous node to the current node
     this.b = parent.b + parent.m[parent.currNode * maxIndex + toNode];
     // create a new m matrix and copy over all the values
     this.m = new double[maxIndex * maxIndex];
     for (int i = 0; i < m.Length; i++)
     {
         this.m[i] = parent.m[i];
     }
     // create a new visited list and copy those values
     this.visited = new List <int>();
     for (int i = 0; i < parent.visited.Count; i++)
     {
         this.visited.Add(parent.visited[i]);
     }
     // update the visited list
     this.visited.Add(toNode);
     this.toNode   = toNode;
     this.currNode = toNode;
     this.fromNode = parent.currNode;
     // mark infinity on the column for the node going to (the child)
     markToNode();
     // mark infinities on the row for the node coming from (the parent)
     markFromNode();
     // mark the awkward diagonal cell in the matrix as inifinity
     markFromToNode();
     // make sure there are still 0 values in row/column
     updateMatrix();
 }
        /// <summary>
        /// performs a Branch and Bound search of the state space of partial tours
        /// stops when time limit expires and uses BSSF as solution
        /// </summary>
        /// <returns>results array for GUI that contains three ints: cost of solution, time spent to find solution, number of solutions found during search (not counting initial BSSF estimate)</returns>
        // This algorithm implements a greedy approach, 10,000 random attempts, and the branch and bound approach with pruning of leaf
        // nodes that have values grater than the current BSSF.
        // O = greedy + 10,000*random + branch and bound
        // = O(n^3 + 10000*n + (2^n)*(n^2) = O((n^2)*(2^n))
        public string[] bBSolveProblem()
        {
            // initialize the variables
            int count = 0;

            string[] results = new string[3];
            int[]    perm    = new int[Cities.Length];
            Route = new ArrayList();
            Stopwatch timer        = new Stopwatch();
            int       maxStates    = 0;
            int       totalStates  = 0;
            int       statesPruned = 0;

            // start the timer
            timer.Start();
            // start BSSF as positive infinity;
            double currSol = Double.PositiveInfinity;
            // see if the BSSF updates with the greedy algorithm
            // Finding greedy solution = O(n^3)
            double greedySol = Convert.ToDouble(greedySolveProblem()[0]);

            if (greedySol < currSol)
            {
                currSol = greedySol;
                count  += 1;
            }
            // attempt updating the BSSF with 10,000 random solutions
            // finding random solution = O(n)
            for (int cycleRand = 0; cycleRand < 10000; cycleRand++)
            {
                double tempSol = Convert.ToInt32(defaultSolveProblem()[0]);
                if (tempSol < currSol)
                {
                    currSol = tempSol;
                    count  += 1;
                }
            }
            // create the List of nodes
            List <DistMatrix> children = new List <DistMatrix>();

            // initialize the first node in the list (root node)
            children.Add(new DistMatrix(Cities));

            // while there are nodes in the node list
            while (children.Count > 0)
            {
                // check if the timer has passed 60 seconds
                timer.Stop();
                long time = timer.ElapsedMilliseconds / 1000;
                if (time >= 60)
                {
                    // if it has passed 60 seconds, break out of the while loop
                    break;
                }
                timer.Start();

                // Find the next node - O(n)
                if (maxStates < children.Count)
                {
                    maxStates = children.Count;
                }
                // collect the variables to find the best child node
                DistMatrix currNode   = children[0];
                double     best       = children[0].b;
                int        numVisited = children[0].visited.Count;
                // for each child node, check if it is optimal
                for (int i = 0; i < children.Count; i++)
                {
                    double value     = children[i].b;
                    int    visited   = children[i].visited.Count;
                    double diffValue = value - best;
                    int    diffVisit = visited - numVisited;
                    // used this little algorithm to try and balance breadth and depth
                    if (value < best * (1 + (diffVisit / .75)))
                    {
                        currNode   = children[i];
                        best       = children[i].b;
                        numVisited = children[i].visited.Count;
                    }
                }
                // remove that node from the list of possiblities
                children.RemoveAt(children.IndexOf(currNode));
                // if the child node has not reached the end
                if (!currNode.finished())
                {
                    // get the list of nodes that haven't been visited
                    List <int> nextChildren;
                    nextChildren = currNode.returnNodesLeft();
                    // create a child object for each of those nodes - O(n^2) happening 2^n times
                    // for the worst case scenario where each leaf must be reached in the tree.
                    // This gives a O((n^2)*(2^n))
                    for (int i = 0; i < nextChildren.Count; i++)
                    {
                        DistMatrix child = new DistMatrix(nextChildren[i], currNode);
                        children.Add(new DistMatrix(nextChildren[i], currNode));
                        totalStates += 1;
                    }
                }
                // if the node is a leaf, check if it's better than the current BSSF
                //O(n) to check each one, with O(n) to check if any need removing after
                // an update on the BSSF.
                else
                {
                    if (currNode.b < currSol)
                    {
                        // if it is better, replace the current BSSF
                        ArrayList   tempRoute = buildRoute(currNode.visited);
                        TSPSolution test      = new TSPSolution(tempRoute);
                        if (test.costOfRoute() < currSol)
                        {
                            Route.Clear();
                            Route   = buildRoute(currNode.visited);
                            bssf    = null;
                            bssf    = new TSPSolution(Route);
                            currSol = costOfBssf();
                            count  += 1;
                        }
                        // filter any children that has a b greater than the current bssf.
                        // remove those children in hopes of speeding up the algorithm
                    }
                }
                for (int i = 0; i < children.Count; i++)
                {
                    if (children[i].b > currSol)
                    {
                        children.RemoveAt(i);
                        statesPruned += 1;
                        i--;
                    }
                }
            }

            // Stop the time and report the results.
            timer.Stop();
            results[COST]  = costOfBssf().ToString(); // load results array
            results[TIME]  = timer.Elapsed.ToString();
            results[COUNT] = count.ToString();
            Console.WriteLine("Max States: {0}, Total States: {1}, Total Pruned: {2}", maxStates, totalStates, statesPruned);
            return(results);
        }