Traversal Salesmane Problem - branch-and-bound

/* Branch-and-Bound solution to the Traveling Salesman Problem.  This is
 * based on the backtracking solution that generates all Hamiltonian
 * paths and then simply reports the smallest one.  Here the bounding
 * function is the length of the path that has already been fixed in the
 * permutation vector.  The presently mutable part of the permutation
 * vector may or may not presently constitute a path --- but some other
 * permutation of that segment may constitute a path.
 *
 * Based on a boolean in the class Tour, one can examine DFS processing:
 * the primary key is the index (reversed to give maxheap behavior),
 * with the secondary key as the distance.  For one specimen dataset
 * (fairly sparse), the same number of Tour objects were generated for
 * the two search options.  DFS, however, found a valid tour very early.
 *
 * Input file specifications:
 *   Number of vertices in the graph (crossroads in the map)
 *   That many lines giving names
 *   one blank line
 *   Lines specifying roads:  two double-quoted names and an integer
 *
 * Language:  Java 1.5.x due to Scanner, enhanced for loop . . .
 *
 * Author:  Timothy Rolfe
 */
import java.util.*;     // Arrays and Collections and . . .

public class TSP_BnB
{
   static int[][]  wt;                 // Matrix of edge weights
   static String[] city;               // Vector of city names
   static int      n;                  // Dimension for wt and city
   static ArrayList<Tour> soln = new ArrayList<Tour>();
   static int      bestTour;           // Initialized in init()
   static int      blocked;            // Ditto
   static boolean  DEBUG   =  true;    // Show accept/reject decisions
   static boolean  VERBOSE =  true;    // Show all tours discovered

   private static class Tour implements Comparable
   {  int[] soln;
      int   index;      // In branch-and-bound, start of variable
      int   dist;
      static int nTours = 0;
      // Best-first based on dist, or DFS based on maxheap of index
      static boolean DFS =  true;
      static boolean DBG =  true;

      /* Presumable edges up to [index-1] have been verified before
       * this constructor has been called.  So compute the fixed
       * distance from [0] up to [index-1] as dist.
       */
      private Tour(int[] vect, int index, int[][] wt)
      {  dist = 0;
         for (int k = 1; k < index; k++)         // Add edges
            dist += wt[vect[k-1]][vect[k]];
         if ( index == n )
            dist += wt[vect[n-1]][vect[0]];      // Return edge
         soln = new int[n];                      // Deep copy
         System.arraycopy(vect, 0, soln, 0, n);
         this.index = index;                     // Index to permute
         nTours++;                               // Count up # of tours
         if ( DBG )
            System.out.printf("Idx %d: %s\n", index, toString() );
      }

      public int compareTo ( Object o )
      {  Tour rt = (Tour)o;
         int  c1 = rt.index - this.index,
              c2 = this.dist - rt.dist;
         if ( DFS )
            return c1 == 0 ? c2 : c1;
         else
            return c2;
      }

      // For debugging convenience:  show the current state.
      public String toString()
      {  StringBuilder val = new StringBuilder( city[soln[0]] );
         for ( int k = 1; k < n; k++ )
            val.append(", " + city[soln[k]]);
         val.append(", " + city[soln[0]]);
         val.append( String.format(" for %d", dist) );
         return val.toString();
      }
   }

   // For debugging convenience:  show state UP TO this index
   private static void partial(int[] vect, int index)
   {  int dist = 0;

      System.out.print (city[vect[0]]);
      for ( int k = 1; k <= index; k++ )
      {  System.out.print (", " + city[vect[k]]);
         dist += wt[vect[k-1]][vect[k]];
      }
      System.out.println (" for distance " + dist);
   }

   // Initialize the global variables based on the file passed through
   // the Scanner inp.  See the header for the specifications of the
   // input file.
   private static void init(Scanner inp)
   {  int sub1,
          sub2;
      String line;

      n = inp.nextInt();
      wt = new int[n][n];
      city = new String[n];
      // Initially, there are NO edges; hence -1.
      for ( sub1 = 0; sub1 < n; sub1++ )
         Arrays.fill(wt[sub1], -1);

      inp.nextLine();   // Discard rest of first line
      for ( sub1 = 0; sub1 < n; sub1++ )
         city[sub1] = inp.nextLine();
      Arrays.sort(city);     // Just to be sure (binarySearch)

      inp.nextLine();   // Discard blank spacing line;
      blocked = 0;      // Accumulate ALL weights for upper bound

      while ( inp.hasNext() )
      {  int    head, tail;
         int    dist;
         String src, dst;

         line = inp.nextLine();   // E.g.:  "George" "Pasco" 91
         // Chop out the double-quoted substrings.
         head = line.indexOf('"') + 1;
         tail = line.indexOf('"', head);
         src = line.substring(head, tail);

         head = line.indexOf('"', tail+1) + 1;
         tail = line.indexOf('"', head);
         dst = line.substring(head, tail);

         dist = Integer.parseInt( line.substring(tail+1).trim() );
         sub1 = Arrays.binarySearch(city, src);
         sub2 = Arrays.binarySearch(city, dst);
         wt[sub1][sub2] = wt[sub2][sub1] = dist;
         blocked += dist;
      }
      blocked += blocked;    // Double the total
      bestTour = blocked;    // And initialize bestTour
   }

   // Used below in generating permutations.
   private static void swap ( int[] x, int p, int q )
   {  int tmp = x[p];  x[p] = x[q]; x[q] = tmp;  }

   // Generate the available tours by branch-and-bound.
   // Generate the initial permutation vector, then save that state
   // as the first examined in the branch-and-bound.
   public  static void tour()
   {  int[] vect = new int[n];
      int   start;
      Queue<Tour> work = new PriorityQueue<Tour>();

      // First permutation vector.
      for ( int k = 0; k < n; k++ )
         vect[k] = k;
      // We will, however, start from Spokane, not Coulee City
      // --- IF the data file is the one for the inland Pacific NW
      start = Arrays.binarySearch(city, "Spokane");
      if ( start >= 0 )
      {  vect[start] = 0; vect[0] = start;  }
      // Consequently, we start the permutations at [1], NOT [0].
      work.add( new Tour(vect, 1, wt) );

      while ( ! work.isEmpty() )  // Branch-and-bound loop
      {
         Tour current = work.poll();
         int  index = current.index;

         vect  = current.soln;

         if ( index == n )        // I.e., Full permutation vector
         {  if ( wt[vect[n-1]][vect[0]] > 0 )    // Return edge?
            {  if ( current.dist < bestTour )    // Better than earlier?
               {//Save the state in the list
                  bestTour = current.dist;
                  soln.add(current);
                  if ( DEBUG )
                     System.out.println("Accept " + current);
               }
               else if ( DEBUG )
                  System.out.println ("Too long:  " + current);
            }
            else if (DEBUG)
               System.out.println(    "Invalid:   " + current);
         }
         else                     // Continue generating permutations
         {
            int k;      // Loop variable
            int hold;   // Used in regenerating the original state

            for ( k = index; k < n; k++ )
            {
               swap ( vect, index, k );
               if ( wt[vect[index-1]][vect[index]] < 0 )
                  continue;
               work.add ( new Tour(vect, index+1, wt) );
            }
            // Restore original permutation
            hold = vect[index];
            for ( k = index+1; k < n; k++ )
               vect[k-1] = vect[k];
            vect[n-1] = hold;
         }
      }
   }


   public static void main (String[] args) throws Exception
   {
      String filename = args.length == 0 ? "RoadSet.txt"
                                         : args[0];
      Scanner inp = new Scanner ( new java.io.File(filename) );

      System.out.println("Data read from file " + filename);
      init(inp);
      tour();

      if (VERBOSE)
      {  System.out.println ("Tours discovered:");
         for ( Tour opt : soln )
            System.out.println(opt);
      }
      if ( soln.size() == 0 )
      {  System.out.println("NO tours discovered.  Exiting.");
         System.exit(0);
      }
      System.out.println (Tour.nTours + " Tour objects generated.");
      Collections.sort(soln);
      System.out.println("Best tour:  ");
      System.out.println(soln.get(0));
   }
}
This is Backtracking:
/* Backtracking solution to the Traveling Salesman Problem.  Generates all
 * Hamiltonian paths through recursion and keep them in a list.  Then
 * simply report the smallest one.  There is no bounding function used.
 * A Tour object is only generated when a complete tour has been found.
 *
 * NOTE:  This implementation generates ALL tours.  With a small change
 * it can be revised to discard solutions worse than the current best
 * solution so far (global bestTour field).
 *
 * Input file expectation:
 *   Number of vertices in the graph (crossroads in the map)
 *   That many lines giving names
 *   one blank line
 *   Lines specifying roads:  two double-quoted names and an integer
 *
 * Language:  Java 1.5.x due to Scanner, enhanced for loop . . .
 *
 * Author:  Timothy Rolfe
 */
import java.util.*;     // Arrays and Collections and . . .

public class TSP_Back
{
   static int[][]  wt;                 // Matrix of edge weights
   static String[] city;               // Vector of city names
   static int      n;                  // Dimension for wt and city
   static ArrayList<Tour> soln = new ArrayList<Tour>();
   static int      bestTour = Integer.MAX_VALUE;
   static boolean  DEBUG   =  true;    // Show accept/reject decisions
   static boolean  VERBOSE =  true;    // Show all tours discovered

   // Comparable allows sorting the ArrayList of solutions for smallest.
   private static class Tour implements Comparable
   {  int[] soln;       // Permutation vector of city subscripts
      int   dist;

      private Tour(int[] vect)
      {  dist = wt[vect[n-1]][vect[0]]; // Start with return edge
         for (int k = 1; k < n; k++)   // Add in all the others
            dist += wt[vect[k-1]][vect[k]];
         soln = new int[n];            // Deep copy of the vector
         System.arraycopy(vect, 0, soln, 0, n);
      }

      public int compareTo ( Object o )
      {  return this.dist - ((Tour)o).dist;  }

      // For debugging convenience:  show the current state.
      public String toString()
      {  StringBuilder val = new StringBuilder(city[soln[0]]);
         for ( int k = 1; k < n; k++ )
            val.append(", " + city[soln[k]]);
         val.append(", " + city[soln[0]]);
         val.append( String.format(" for %d", dist) );
         return val.toString();
      }
   }

   // For debugging convenience:  show state UP TO this index
   private static void partial(int[] vect, int index)
   {  int dist = 0;

      System.out.print (city[vect[0]]);
      for ( int k = 1; k <= index; k++ )
      {  System.out.print (", " + city[vect[k]]);
         dist += wt[vect[k-1]][vect[k]];
      }
      System.out.println (" for distance " + dist);
   }

   // Initialize the global variables based on the file passed through
   // the Scanner inp.  See the header documentation for the
   // specifications for the input file.
   private static void init(Scanner inp)
   {  int sub1,
          sub2;
      String line;

      n = inp.nextInt();
      wt = new int[n][n];
      city = new String[n];
      // Initially, there are NO edges; hence -1.
      for ( sub1 = 0; sub1 < n; sub1++ )
         Arrays.fill(wt[sub1], -1);

      inp.nextLine();   // Discard rest of first line
      for ( sub1 = 0; sub1 < n; sub1++ )
         city[sub1] = inp.nextLine();
      Arrays.sort(city);     // Just to be sure (binarySearch)

      inp.nextLine();   // Discard blank spacing line;

      while ( inp.hasNext() )
      {  int    head, tail;
         int    dist;
         String src, dst;

         line = inp.nextLine();   // E.g.:  "George" "Pasco" 91
         // Chop out the double-quoted substrings.
         head = line.indexOf('"') + 1;
         tail = line.indexOf('"', head);
         src = line.substring(head, tail);

         head = line.indexOf('"', tail+1) + 1;
         tail = line.indexOf('"', head);
         dst = line.substring(head, tail);

         dist = Integer.parseInt( line.substring(tail+1).trim() );
         sub1 = Arrays.binarySearch(city, src);
         sub2 = Arrays.binarySearch(city, dst);
         wt[sub1][sub2] = wt[sub2][sub1] = dist;
      }
   }

   // Public access for generating the tours.
   // Generate the initial permutatio vector, then call recursive tour
   public  static void tour()
   {
      int[] vect = new int[n];
      int   start = Arrays.binarySearch(city, "Spokane");

      // First permutation vector.
      for ( int k = 0; k < n; k++ )
         vect[k] = k;
      // We will, however, start from Spokane, not Coulee City
      // --- IF the data file is the one for the inland Pacific NW
      start = Arrays.binarySearch(city, "Spokane");
      if ( start >= 0 )
      {  vect[start] = 0; vect[0] = start;  }
      // Consequently, we start the permutations at [1], NOT [0].
      tour(1, vect);
   }

   // Used below in generating permutations.
   private static void swap ( int[] x, int p, int q )
   {  int tmp = x[p];  x[p] = x[q]; x[q] = tmp;  }

   // Recursive generation of the permutatio vectors that constitute
   // possible paths.
   private static void tour(int index, int[] vect)
   {
      if ( index == n )      // I.e., we have a full permutation vector
      {  Tour current;

         if ( wt[vect[n-1]][vect[0]] > 0 )  // IS there a return edge?
         {//Save the state in the list
            current = new Tour(vect);
            bestTour = Math.min(current.dist, bestTour);
            soln.add(current);
            if ( DEBUG )
               System.out.println("Accept " + current);
         }
         else if (DEBUG)
         {  System.out.print ("Reject "); partial ( vect, n-1 );  }
      }
      else                   // Continue generating permutations
      {
         int k;         // Loop variable
         int hold;      // Used in regenerating the original state

         for ( k = index; k < n; k++ )
         {
            swap ( vect, index, k );
            if ( wt[vect[index-1]][vect[index]] < 0 )
               continue;
            tour ( index+1, vect );
         }
         // Restore permutation
         hold = vect[index];
         for ( k = index+1; k < n; k++ )
            vect[k-1] = vect[k];
         vect[n-1] = hold;
      }
   }

   public static void main (String[] args) throws Exception
   {
      String filename = args.length == 0 ? "RoadSet.txt"
                                         : args[0];
      Scanner inp = new Scanner ( new java.io.File(filename) );

      System.out.println("Data read from file " + filename);
      init(inp);
      tour();

      if (VERBOSE)
      {  System.out.println ("Tours discovered:");
         for ( Tour opt : soln )
            System.out.println(opt);
      }
      if ( soln.size() == 0 )
         System.out.println("NO tours discovered.  Exiting.");
      else
      {  Collections.sort(soln);
         System.out.println("Best tour:  ");
         System.out.println(soln.get(0));
         System.out.println("Worst tour:  ");
         // First of the pair with this total.
         System.out.println(soln.get(soln.size()-2));
      }
   }
}
/* Run with DEBUG false and VERBOSE true
Data read from file Levitin.txt
Tours discovered:
a, b, c, d, e, a for 24
a, b, c, e, d, a for 19
a, b, d, c, e, a for 24
a, b, d, e, c, a for 16
a, b, e, c, d, a for 23
a, b, e, d, c, a for 20
a, c, b, d, e, a for 25
a, c, b, e, d, a for 24
a, c, d, b, e, a for 29
a, c, d, e, b, a for 20
a, c, e, b, d, a for 24
a, c, e, d, b, a for 16
a, d, b, c, e, a for 28
a, d, b, e, c, a for 24
a, d, c, b, e, a for 32
a, d, c, e, b, a for 23
a, d, e, b, c, a for 24
a, d, e, c, b, a for 19
a, e, b, c, d, a for 32
a, e, b, d, c, a for 29
a, e, c, b, d, a for 28
a, e, c, d, b, a for 24
a, e, d, b, c, a for 25
a, e, d, c, b, a for 24
Best tour:
a, b, d, e, c, a for 16
Worst tour:
a, d, c, b, e, a for 32
*/

http://penguin.ewu.edu/cscd501/Wint-2008/BranchAndBound/TSP/index.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值