Open In App

Bitonic Travelling Salesman Problem

Last Updated : 12 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given a 2D array, arr[][] denoting a list of coordinates of N vertices on 2D space that is already sorted by x-coordinates and y-coordinates, the task is to find the minimum distance of a tour that starts from the leftmost vertex, and strictly goes to the right, and then upon reaching the rightmost vertex, the tour goes strictly from right to left-back to the starting vertex. 

Examples:

Input: N = 7, arr[][] = {{0, 6}, {1 0}, {2 3}, {5 4}, {6 1}, {7 5}, {8 2}}
Output: 25.582
Explanation: 

The TSP tour: 0-3-5-6-4-1-2-0 is not a Bitonic TSP tour because although the tour initially goes from left to right (0-3-5-6) and then goes back from right to left (6-4-1), it then makes another left to right (1-2) and then right to left (2-0) steps. 
The tour: 0-2-3-5-6-4-1-0 is a valid Bitonic TSP tour because it can be decomposed into two paths: 0-2-3-5-6 that goes from left to right and 6-4-1-0 that goes back from right to left.

Input: N = 3, arr[][] = {{1, 1}, {2, 3}, {3, 1}}
Output: 6.47

Approach: The above problem can be solved using Dynamic Programming. For the sake of understanding, the problem can be changed into two people. Both should start from the leftmost point at the same time. Walk along two different paths, and finally reach the rightmost point, except for the starting point and the endpoint.

  • Every point happens to be passed by one person. Here, dp[i][j] represents how far the first person walks to i and the second person walks to j.
  • In the solution, dp[i][j] means that 1 to max(i, j) have all been walked, and the current positions of the two people are i and j respectively, and how far they need to go.
  • Also, it can be inferred that dp[i][j] is equal to dp[j][i], so from now on it is stipulated that i is always greater than j i.e. i>j in the state.
  • In this way, no matter that person, the next step can only go to i+1, i+2,… these points.
  • So, the state dp[i][j] can only be transferred to dp[i+1][j] or dp[i][i+1].

Follow the steps below to solve the problem:

  • Create a 2D array, dp[][] of size N*N. 
  • Iterate the last row of the table, dp, and update dp[N-1][i] to the sum of distance(N-1, N) and distance(i, N), where distance(x, y) represents the Euclidean distance between xth and yth points of arr.
  • Create a recursive function findTour(i, j) to fill all other cells
    • Update dp[i][j] to minimum of findTour(i+1, j)+distance(i, i+1) and findTour(i+1, i)+distance(j, i+1).

Below is the implementation of the above approach:

C++
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;

// Size of the array a[]
const int mxN = 1005;

// Structure to store the x and
// y coordinates of a point
struct Coordinates {
    double x, y;
} a[mxN];

// Declare a 2-D dp array
float dp[mxN][mxN];

// Function to calculate the
// distance between two points
// in a Euclidean plane
float distance(int i, int j)
{
    // Return the distance
    return sqrt(
      (a[i].x - a[j].x) * (a[i].x - a[j].x)
    + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}

// Utility recursive function to find
// the bitonic tour distance
float findTourDistance(int i, int j)
{
    // Memoization
    if (dp[i][j] > 0)
        return dp[i][j];

    // Update dp[i][j]
    dp[i][j] = min(
    findTourDistance(i + 1, j) + distance(i, i + 1),
    findTourDistance(i + 1, i) + distance(j, i + 1));

    return dp[i][j];
}

// Function to find the
// bitonic tour distance
void bitonicTSP(int N)
{
    // Initialize the dp array
    memset(dp, 0, sizeof(dp));

    // Base Case
    for (int j = 1; j < N - 1; j++)
        dp[N - 1][j] = distance(N - 1, N)
              + distance(j, N);

    // Print the answer
    printf("%.2f\n", findTourDistance(1, 1));
}

// Driver Code
int main()
{
    // Given Input
    int N = 3;
    a[1].x = 1, a[1].y = 1;
    a[2].x = 2, a[2].y = 3;
    a[3].x = 3, a[3].y = 1;

    // Function Call
    bitonicTSP(N);
}
Java
import java.util.Arrays;

public class Main {
    // Size of the array a[]
    private static final int mxN = 1005;

    // Structure to store the x and
    // y coordinates of a point
    private static class Coordinates {
        double x, y;
    }

    private static Coordinates[] a = new Coordinates[mxN];

    // Declare a 2-D dp array
    private static float[][] dp = new float[mxN][mxN];

    // Function to calculate the
    // distance between two points
    // in a Euclidean plane
    private static float distance(int i, int j)
    {
        // Return the distance
        return (float)Math.sqrt(
            (a[i].x - a[j].x) * (a[i].x - a[j].x)
            + (a[i].y - a[j].y) * (a[i].y - a[j].y));
    }

    // Utility recursive function to find
    // the bitonic tour distance
    private static float findTourDistance(int i, int j)
    {
        // Memoization
        if (dp[i][j] > 0) {
            return dp[i][j];
        }

        // Update dp[i][j]
        dp[i][j] = Math.min(findTourDistance(i + 1, j)
                                + distance(i, i + 1),
                            findTourDistance(i + 1, i)
                                + distance(j, i + 1));

        return dp[i][j];
    }

    // Function to find the
    // bitonic tour distance
    private static void bitonicTSP(int N)
    {
        // Initialize the dp array
        for (float[] row : dp) {
            Arrays.fill(row, 0);
        }

        // Base Case
        for (int j = 1; j < N - 1; j++) {
            dp[N - 1][j]
                = distance(N - 1, N) + distance(j, N);
        }

        // Print the answer
        System.out.printf("%.2f\n", findTourDistance(1, 1));
    }

    // Driver Code
    public static void main(String[] args)
    {
        // Given Input
        int N = 3;
        a[1] = new Coordinates();
        a[1].x = 1;
        a[1].y = 1;
        a[2] = new Coordinates();
        a[2].x = 2;
        a[2].y = 3;
        a[3] = new Coordinates();
        a[3].x = 3;
        a[3].y = 1;

        // Function Call
        bitonicTSP(N);
    }
}
C#
using System;
using System.Linq;

class MainClass
{
  
  // Size of the array a[]
  private static readonly int mxN = 1005;

  // Structure to store the x and
  // y coordinates of a point
  private struct Coordinates { public double x, y; }

  private static Coordinates[] a = new Coordinates[mxN];

  // Declare a 2-D dp array
  private static float[, ] dp = new float[mxN, mxN];

  // Function to calculate the
  // distance between two points
  // in a Euclidean plane
  private static float distance(int i, int j)
  {
    // Return the distance
    return (float)Math.Sqrt(
      (a[i].x - a[j].x) * (a[i].x - a[j].x)
      + (a[i].y - a[j].y) * (a[i].y - a[j].y));
  }

  // Utility recursive function to find
  // the bitonic tour distance
  private static float findTourDistance(int i, int j)
  {
    
    // Memoization
    if (dp[i, j] > 0) {
      return dp[i, j];
    }

    // Update dp[i][j]
    dp[i, j] = Math.Min(findTourDistance(i + 1, j)
                        + distance(i, i + 1),
                        findTourDistance(i + 1, i)
                        + distance(j, i + 1));

    return dp[i, j];
  }


  // Function to find the
  // bitonic tour distance
  public static void bitonicTSP(int N)
  {
    // Initialize the dp array
    for (int i = 0; i < mxN; i++) {
      for (int j = 0; j < mxN; j++) {
        dp[i, j] = 0;
      }
    }

    // Base Case
    for (int j = 1; j < N - 1; j++) {
      dp[N - 1, j]
        = distance(N - 1, N) + distance(j, N);
    }

    // Print the answer
    Console.WriteLine("{0:0.00}",
                      findTourDistance(1, 1));
  }

  // Driver Code
  public static void Main(String[] args)
  {
    
    // Given Input
    int N = 3;
    a[1] = new Coordinates();
    a[1].x = 1;
    a[1].y = 1;
    a[2] = new Coordinates();
    a[2].x = 2;
    a[2].y = 3;
    a[3] = new Coordinates();
    a[3].x = 3;
    a[3].y = 1;

    // Function Call
    bitonicTSP(N);
  }
}

// This code is contributed by divya_p123.
Javascript
// Javascript program for the above approach

// Size of the array a[]
const mxN = 1005;

// Structure to store the x and
// y coordinates of a point
class Coordinates {
    constructor(x,y)
    {
        this.x=x;
        this.y=y;
    }
}

// Declare a 2-D dp array
let dp=new Array(mxN);
for(let i=0; i<mxN; i++)
    dp[i]=new Array(mxN);

// Function to calculate the
// distance between two points
// in a Euclidean plane
function distance( i, j)
{
    // Return the distance
    return Math.sqrt(
      (a[i].x - a[j].x) * (a[i].x - a[j].x)
    + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}

// Utility recursive function to find
// the bitonic tour distance
function findTourDistance( i,  j)
{
    // Memoization
    if (dp[i][j] > 0)
        return dp[i][j];

    // Update dp[i][j]
    dp[i][j] = Math.min(
    findTourDistance(i + 1, j) + distance(i, i + 1),
    findTourDistance(i + 1, i) + distance(j, i + 1));

    return dp[i][j];
}

// Function to find the
// bitonic tour distance
function bitonicTSP( N)
{
    // Initialize the dp array
    for(let i=0; i<mxN; i++)
    {
        for(let j=0; j<mxN; j++)
            dp[i][j]=-1;
    }
    // Base Case
    for (let j = 1; j < N - 1; j++)
        dp[N - 1][j] = distance(N - 1, N)
              + distance(j, N);

    // Print the answer
    console.log(parseFloat(findTourDistance(1, 1)).toFixed(2));
}

// Driver Code
// Given Input
let a=[];
let N = 3;
a[1]=new Coordinates(1,1);
a[2]=new Coordinates(2,3);
a[3]=new Coordinates(3,1);

// Function Call
bitonicTSP(N);
Python3
import math

N = 3

# Structure to store the x and y coordinates of a point
a = [{"x": 0, "y": 0} for _ in range(N+1)]

# Declare a 2-D dp array
dp = [[0 for _ in range(N+1)] for _ in range(N+1)]

# Given Input
a[1]['x'] = 1
a[1]['y'] = 1
a[2]['x'] = 2
a[2]['y'] = 3
a[3]['x'] = 3
a[3]['y'] = 1

# Function to calculate the distance between two points in a Euclidean plane


def distance(i, j):
    return math.sqrt((a[i]['x'] - a[j]['x']) ** 2 + (a[i]['y'] - a[j]['y']) ** 2)

# Utility recursive function to find the bitonic tour distance


def findTourDistance(i, j):
    # Memoization
    if dp[i][j] > 0:
        return dp[i][j]

    # Update dp[i][j]
    dp[i][j] = min(findTourDistance(i+1, j) + distance(i, i+1),
                   findTourDistance(i+1, i) + distance(j, i+1))

    return dp[i][j]

# Function to find the bitonic tour distance


def bitonicTSP(N):
    # Initialize the dp array
    for i in range(N+1):
        for j in range(N+1):
            dp[i][j] = 0

    # Base Case
    for j in range(1, N-1):
        dp[N-1][j] = distance(N-1, N) + distance(j, N)

    # Print the answer
    print("%.2f" % findTourDistance(1, 1))


# Function Call
bitonicTSP(N)

Output
6.47



Time Complexity: O(N2)
Auxiliary Space: O(N2)

Efficient Approach: Using the DP Tabulation method(Iterative Approach) – The approach to solve this problem is the same but DP tabulation(bottom-up) method is better than the Dp + memoization(top-down) because the memoization method needs extra stack space of recursion calls.

Steps to solve this problem:

Follow the steps below to solve the problem:

  • Create a 2D array, dp[][] of size N*N. 
  • Iterate the last row of the table, dp, and update dp[N-1][i] to the sum of distance(N-1, N) and distance(i, N), where distance(x, y) represents the Euclidean distance between xth and yth points of arr.
  • Create a recursive function findTour(i, j) to fill all other cells
    • Update dp[i][j] to minimum of findTour(i+1, j)+distance(i, i+1) and findTour(i+1, i)+distance(j, i+1).
  • Create a DP to store the solution of the subproblems and initialize it with 0.
  • Initialize the DP with base cases
  • Now Iterate over subproblems to get the value of the current problem from the previous computation of subproblems as dp[i + 1][j] + distance(i, i+1) and dp[i + 1][i] + distance(j, i+1) and stored in the DP table.
  • The value of dp[1][1] gives the resultant value.

Below is the implementation of the above approach:

C++
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;

// Size of the array a[]
const int mxN = 1005;

// Structure to store the x and
// y coordinates of a point
struct Coordinates {
    double x, y;
} a[mxN];

// Declare a 2-D dp array
float dp[mxN][mxN];

// Function to calculate the
// distance between two points
// in a Euclidean plane
float distance(int i, int j) {
    
    // Return the distance
    return sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x)
              + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}

// Function to find the
// bitonic tour distance
void bitonicTSP(int N) {
    // Initialize the dp array
    memset(dp, 0, sizeof(dp));
    
    // Initialize the dp array
    for (int j = 1; j < N - 1; j++)
        dp[N - 1][j] = distance(N - 1, N) + distance(j, N);

    // Calculate dp values in a bottom-up manner
    for (int i = N - 2; i >= 1; i--) {
        for (int j = i; j >= 1; j--) {
            dp[i][j] = min(dp[i + 1][j] + distance(i, i + 1),
                           dp[i + 1][i] + distance(j, i + 1));
        }
    }
    
    // Print the answer
    printf("%.2f\n", dp[1][1]);
}

// Driver Code
int main() {
    
    // Given Input
    int N = 3;
    a[1].x = 1, a[1].y = 1;
    a[2].x = 2, a[2].y = 3;
    a[3].x = 3, a[3].y = 1;
    
    // Function Call
    bitonicTSP(N);
    return 0;
}

// --- by bhardwajji
Java
import java.util.Arrays;

public class Main {

    // Size of the array a[]
    static final int mxN = 1005;

    // Structure to store the x and
    // y coordinates of a point
    static class Coordinates {
        double x, y;

        Coordinates(double x, double y) {
            this.x = x;
            this.y = y;
        }
    }

    static Coordinates[] a = new Coordinates[mxN];

    // Declare a 2-D dp array
    static float[][] dp = new float[mxN][mxN];

    // Function to calculate the
    // distance between two points
    // in a Euclidean plane
    static float distance(int i, int j) {

        // Return the distance
        return (float) Math.sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x)
                + (a[i].y - a[j].y) * (a[i].y - a[j].y));
    }

    // Function to find the
    // bitonic tour distance
    static void bitonicTSP(int N) {
        // Initialize the dp array
        for (int i = 0; i < mxN; i++) {
            Arrays.fill(dp[i], Float.MAX_VALUE);
        }

        // Initialize the dp array
        for (int j = 1; j < N - 1; j++)
            dp[N - 1][j] = distance(N - 1, N) + distance(j, N);

        // Calculate dp values in a bottom-up manner
        for (int i = N - 2; i >= 1; i--) {
            for (int j = i; j >= 1; j--) {
                dp[i][j] = Math.min(dp[i + 1][j] + distance(i, i + 1),
                        dp[i + 1][i] + distance(j, i + 1));
            }
        }

        // Print the answer
        System.out.printf("%.2f\n", dp[1][1]);
    }

    // Driver Code
    public static void main(String[] args) {

        // Given Input
        int N = 3;
        a[1] = new Coordinates(1, 1);
        a[2] = new Coordinates(2, 3);
        a[3] = new Coordinates(3, 1);

        // Function Call
        bitonicTSP(N);
    }
}
C#
using System;

// Structure to store the x and
// y coordinates of a point
public struct Coordinates
{
    public double x, y;
}

public class Program
{
    // Size of the array a[]
    static readonly int mxN = 1005;

    // Declare a 2-D dp array
    static float[,] dp = new float[mxN, mxN];
    static Coordinates[] a = new Coordinates[mxN];

    // Function to calculate the
    // distance between two points
    // in a Euclidean plane
    static float distance(int i, int j)
    {
        // Return the distance
        return (float)Math.Sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x)
                  + (a[i].y - a[j].y) * (a[i].y - a[j].y));
    }

    // Function to find the
    // bitonic tour distance
    static void bitonicTSP(int N)
    {
        // Initialize the dp array
        Array.Clear(dp, 0, dp.Length);

        // Initialize the dp array
        for (int j = 1; j < N - 1; j++)
            dp[N - 1, j] = distance(N - 1, N) + distance(j, N);

        // Calculate dp values in a bottom-up manner
        for (int i = N - 2; i >= 1; i--)
        {
            for (int j = i; j >= 1; j--)
            {
                dp[i, j] = Math.Min(dp[i + 1, j] + distance(i, i + 1),
                           dp[i + 1, i] + distance(j, i + 1));
            }
        }

        // Print the answer
        Console.WriteLine("{0:F2}", dp[1, 1]);
    }

    // Driver Code
    static void Main()
    {
        // Given Input
        int N = 3;
        a[1] = new Coordinates { x = 1, y = 1 };
        a[2] = new Coordinates { x = 2, y = 3 };
        a[3] = new Coordinates { x = 3, y = 1 };

        // Function Call
        bitonicTSP(N);
    }
}
Javascript
// Structure to store the x and y coordinates of a point
class Coordinates {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

// Size of the array a[]
const mxN = 1005;
// Declare a 2-D dp array
let dp = new Array(mxN).fill().map(() => new Array(mxN).fill(0));
// Array to store coordinates
let a = new Array(mxN);

// Function to calculate the distance between two points in a Euclidean plane
function distance(i, j) {
    // Return the distance
    return Math.sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}

// Function to find the bitonic tour distance
function bitonicTSP(N) {
    // Initialize the dp array
    for (let j = 1; j < N - 1; j++)
        dp[N - 1][j] = distance(N - 1, N) + distance(j, N);

    // Calculate dp values in a bottom-up manner
    for (let i = N - 2; i >= 1; i--) {
        for (let j = i; j >= 1; j--) {
            dp[i][j] = Math.min(dp[i + 1][j] + distance(i, i + 1), dp[i + 1][i] + distance(j, i + 1));
        }
    }

    // Print the answer
    console.log(dp[1][1].toFixed(2));
}

// Driver Code
function main() {
    // Given Input
    let N = 3;
    a[1] = new Coordinates(1, 1);
    a[2] = new Coordinates(2, 3);
    a[3] = new Coordinates(3, 1);

    // Function Call
    bitonicTSP(N);
}

main();
Python3
import math

# Size of the array a[]
mxN = 1005

# Structure to store the x and y coordinates of a point
class Coordinates:
    def __init__(self, x, y):
        self.x = x
        self.y = y

a = [Coordinates(0, 0) for i in range(mxN)]

# Declare a 2-D dp array
dp = [[0 for j in range(mxN)] for i in range(mxN)]

# Function to calculate the
# distance between two points
# in a Euclidean plane
def distance(i, j):
    # Return the distance
    return math.sqrt((a[i].x - a[j].x) ** 2
              + (a[i].y - a[j].y) ** 2)

# Function to find the
# bitonic tour distance
def bitonicTSP(N):
    # Initialize the dp array
    for i in range(N+1):
        for j in range(N+1):
            dp[i][j] = 0
    
    # Initialize the dp array
    for j in range(1, N - 1):
        dp[N - 1][j] = distance(N - 1, N) + distance(j, N)

    # Calculate dp values in a bottom-up manner
    for i in range(N - 2, 0, -1):
        for j in range(i, 0, -1):
            dp[i][j] = min(dp[i + 1][j] + distance(i, i + 1),
                           dp[i + 1][i] + distance(j, i + 1))
    
    # Print the answer
    print("{:.2f}".format(dp[1][1]))

# Driver Code
if __name__ == '__main__':
    
    # Given Input
    N = 3
    a[1].x, a[1].y = 1, 1
    a[2].x, a[2].y = 2, 3
    a[3].x, a[3].y = 3, 1
    
    # Function Call
    bitonicTSP(N)


Output

6.47

Time Complexity: O(N2)
Auxiliary Space: O(N2)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads