/// <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); }