/// <summary>
        /// Backtrack to get the path of the travelling salesman route
        /// </summary>
        /// <param name="parentDict">dictionary with the parent of the city info.
        /// the back tracking will be done as shown below:
        /// [[0,1,2,3], 1] = 3
        /// [[0,2,3], 3] =  2
        /// [[0,2], 2] = 1
        /// [[0], 0] = 0
        ///
        /// </param>
        /// <param name="finalDestinationBeforeComingToStart">desitnation before coming back to the city from which TS started</param>
        /// <returns></returns>
        public List <int> BackTrackToGetPath(Dictionary <CitySetWithEndPoint, int> parentDict, int finalDestinationBeforeComingToStart)
        {
            List <int> travellingSalesmanRoute = new List <int> {
                StartPoint
            };
            CitySetWithEndPoint lastSet = new CitySetWithEndPoint(new HashSet <int>(AllCitiesExceptStartSet), finalDestinationBeforeComingToStart);

            lastSet.SetOfCities.Add(StartPoint);

            int currentCity = finalDestinationBeforeComingToStart;

            while (currentCity != -1)
            {
                travellingSalesmanRoute.Add(currentCity);

                int previousCity = parentDict[lastSet];
                lastSet.SetOfCities.Remove(currentCity);
                lastSet.EndPoint = previousCity;

                currentCity = previousCity;
            }
            travellingSalesmanRoute.Reverse();
            return(travellingSalesmanRoute);
        }
        /// <summary>
        /// The dynamic programming approach will involve storing the cost for a city subset and endpoint in a Dictionary.
        /// if C(S,j) is the cost of going from StartPoint to j when we have a set of cities belong to S.
        /// C(S,j) = min{C(S-{j}, i) + DistanceMat[i,j]} where i belongs to S-{j}
        ///
        /// The running time of this algo is O((2^n)(n^2))
        /// the total number of subproblems are O((2^n)n) and each subproblem takes n time.
        /// </summary>
        /// <returns>the shortest route for the salesman</returns>
        public List <int> GetShortestRoute()
        {
            // initialization
            Dictionary <CitySetWithEndPoint, int> costOfPath = new Dictionary <CitySetWithEndPoint, int>();
            Dictionary <CitySetWithEndPoint, int> parentDict = new Dictionary <CitySetWithEndPoint, int>();
            CitySetWithEndPoint startSetWithStartPoint       = new CitySetWithEndPoint(new HashSet <int>()
            {
                StartPoint
            }, StartPoint);

            costOfPath[startSetWithStartPoint] = 0;
            parentDict[startSetWithStartPoint] = -1;
            int minPathDistance = int.MaxValue;
            int finalDestinationBeforeComingToStart = -1;

            for (int sizeOfSet = 2; sizeOfSet <= TotalNumOfCities; sizeOfSet++)
            {
                // for each size of the set get all the possible subsets that can be formed
                // the subset should contain the startCity
                List <HashSet <int> > allSubsets = GetAllSubSetOfSize(sizeOfSet);
                foreach (HashSet <int> subSet in allSubsets)
                {
                    foreach (int city in subSet)
                    {
                        // city represents j
                        if (city != StartPoint)
                        {
                            // this represents S
                            CitySetWithEndPoint currentSetAndEndpoint = new CitySetWithEndPoint(subSet, city);

                            foreach (int intermediateCity in subSet)
                            {
                                // intermediateCity represents i
                                if (intermediateCity != city)
                                {
                                    // This will make a clone of the currentSetAndEndpoint object
                                    // this represents S-{j}
                                    CitySetWithEndPoint intermediateSetAndEndpoint = new CitySetWithEndPoint(currentSetAndEndpoint);
                                    intermediateSetAndEndpoint.SetOfCities.Remove(city);
                                    intermediateSetAndEndpoint.EndPoint = intermediateCity;

                                    // get the min for costOfPath[currentSetAndEndpoint]
                                    int initPathCost = int.MaxValue;
                                    if (GetDistanceFromCostPathDict(costOfPath, intermediateSetAndEndpoint) != int.MaxValue)
                                    {
                                        initPathCost = GetDistanceFromCostPathDict(costOfPath, intermediateSetAndEndpoint) + DistanceMat[intermediateCity, city];
                                    }
                                    if (GetDistanceFromCostPathDict(costOfPath, currentSetAndEndpoint) > initPathCost)
                                    {
                                        costOfPath[currentSetAndEndpoint] = initPathCost;
                                        parentDict[currentSetAndEndpoint] = intermediateCity;

                                        // this will keep track of the min path cost and distance from
                                        if (sizeOfSet == TotalNumOfCities && DistanceMat[city, StartPoint] != int.MaxValue && initPathCost + DistanceMat[city, StartPoint] < minPathDistance)
                                        {
                                            minPathDistance = initPathCost + DistanceMat[city, StartPoint];
                                            finalDestinationBeforeComingToStart = city;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (finalDestinationBeforeComingToStart == -1)
            {
                // there is no travelling salesman route
                return(null);
            }
            else
            {
                // backtrack and return the path
                return(BackTrackToGetPath(parentDict, finalDestinationBeforeComingToStart));
            }
        }
            /// <summary>
            /// Needed to make sure that dictionary keys with same set and endpoints gets matched.
            /// The hashset comparison should not check for order in the hashset
            /// </summary>
            /// <param name="obj"></param>
            /// <returns></returns>
            public override bool Equals(object obj)
            {
                CitySetWithEndPoint compObj = (CitySetWithEndPoint)obj;

                return(EndPoint == compObj.EndPoint && SetOfCities.SetEquals(compObj.SetOfCities));
            }
 public CitySetWithEndPoint(CitySetWithEndPoint objToClone)
 {
     SetOfCities = new HashSet <int>(objToClone.SetOfCities);
     EndPoint    = objToClone.EndPoint;
 }
        /// <summary>
        /// If the key c is present in the dictionary costOfPath then return the cost of the path,
        /// else return infinty, denoted by int.MaxValue
        /// </summary>
        /// <param name="costOfPath"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        public int GetDistanceFromCostPathDict(Dictionary <CitySetWithEndPoint, int> costOfPath, CitySetWithEndPoint c)
        {
            int cost = int.MaxValue;

            if (costOfPath.ContainsKey(c))
            {
                cost = costOfPath[c];
            }
            return(cost);
        }