Travelling Salesman Problem (TSP) using Reduced Matrix Method
Last Updated : 23 Jul, 2025
Given a set of cities and the distance between every pair of cities, the problem is to find the shortest possible route that visits every city exactly once and returns to the starting point.
Examples:
Input:
Example of connections of cities
Output: 80 Explanation: An optimal path is 1 - 2 - 4 - 3 - 1.
Dynamic Programming Approach: This approach is already discussed in Set-1 of this article.
Branch and Bound Approach: The branch and bound approach is already discussed in this article.
Reduced Matrix: This approach is similar to the Branch and Bound approach. The difference here is that the cost of the path and the bound is decided based on the method of matrix reduction. The following are the assumptions for a reduced matrix:
A row or column of the cost adjacency matrix is said to be reduced if and only if it contains at least one zero element and all remaining entries in that row or column ≥ 0.
If all rows and columns are reduced then only the matrix is reduced matrix.
Tour length (new) = Tour length (old) – Total value reduced.
We first rewrite the original cost adjacency matrix by replacing all diagonal elements from 0 to Infinity
The basic idea behind solving the problem is:
The cost to reduce the matrix initially is the minimum possible cost for the travelling salesman problem.
Now in each step, we need to decide the minimum possible cost if that path is taken i.e., a path from vertex u to v is followed.
We can do that by replacing uth row and vth column cost by infinity and then further reducing the matrix and adding the extra cost for reduction and cost of edge (u, v) with the already calculated minimum path cost.
Once at least one path cost is found, that is then used as upper bound of cost to apply the branch and bound method on the other paths and the upper bound is updated accordingly when a path with lower cost is found.
Following are the steps to implement the above procedure:
Step1: Create a class (Node) that can store the reduced matrix, cost, current city number, level (number of cities visited so far), and path visited till now.
Step2: Create a priority queue to store the live nodes with the minimum cost at the top.
Step3: Initialize the start index with level = 0 and reduce the matrix. Calculate the cost of the given matrix by reducing the row and then the column. The cost is calculated in the following way:
Row reduction - Find the min value for each row and store it. After finding the min element from each row, subtract it from all the elements in that specific row.
Column reduction - Find the min value for each column and store it. After finding the min element from each column, subtract it from all the elements in that specific column. Now the matrix is reduced.
Now add all the minimum elements in the row and column found earlier to get the cost.
Step4: Push the element with all information required by Node into the Priority Queue.
Step5: Now, perform the following operations till the priority queue gets empty.
Pop the element with the min value from the priority queue.
For each pop operation check whether the level of the current node is equal to the number of nodes/cities or not.
If yes then print the path and return the minimum cost.
If No then, for each and every child node of the current node calculate the cost by using the formula- Child->Cost = parent_matrix_cost + cost_from_parentTochild + Child_reducedMatrix_cost.
The cost of a reduced Matrix can be calculated by converting all the values of its rows and column to infinity and also making the index Matrix[Col][row] = infinity.
Then again push the current node into the priority queue.
Step6: Repeat Step5 till we don't reach the level = Number of nodes - 1.
Follow the illustration below for a better understanding.
Illustration:
Consider the connections as shown in the graph:
Example of connections
Initially the cost matrix looks like:
row/col no
1
2
3
4
1
-
10
15
20
2
10
-
35
25
3
15
35
-
30
4
20
25
30
-
After row and column reduction the matrix will be:
row/col no
1
2
3
4
1
-
0
5
10
2
0
-
25
15
3
0
20
-
15
4
0
5
10
-
and row minimums are 10, 10, 15 and 20.
row/col no
1
2
3
4
1
-
0
0
0
2
0
-
20
5
3
0
20
-
5
4
0
5
5
-
and the column minimums are 0, 0, 5 and 10. So the cost reduction of the matrix is (10 + 10 + 15 + 20 + 5 + 10) = 70
Now let us consider movement from 1 to 2: Initially after substituting the 1st row and 2nd column to infinity, the matrix will be:
row/col no
1
2
3
4
1
-
-
-
-
2
-
-
20
5
3
0
-
-
5
4
0
-
5
-
After the matrix is reduced the row minimums will be 5, 0, 0
row/col no
1
2
3
4
1
-
-
-
-
2
-
-
15
0
3
0
-
-
5
4
0
-
5
-
and the column minimum will be 0, 5, 0
row/col no
1
2
3
4
1
-
-
-
-
2
-
-
10
0
3
0
-
-
5
4
0
-
0
-
So the cost will be 70 + cost (1, 2) + 5 + 5 = 70 + 0 + 5 + 5 = 80.
Continue this process till the traversal is complete and find the minimum cost.
Given below the structure of the recursion tree along with the bounds:
The recursion diagram with bounds
Below is the implementation of the above approach.
C++
// C++ code to implement the approach#include<bits/stdc++.h>usingnamespacestd;// N is the number of cities/Node given#define N 4#define INF INT_MAX// Structure to store all the necessary information // to form state space treestructNode{// Helps in tracing the path when the answer is found// stores the edges of the path // completed till current visited nodevector<pair<int,int>>path;// Stores the reduced matrixintreducedMatrix[N][N];// Stores the lower boundintcost;// Stores the current city numberintvertex;// Stores the total number of cities visitedintlevel;};// Formation of edges and assigning // all the necessary information for new nodeNode*newNode(intparentMatrix[N][N],vector<pair<int,int>>const&path,intlevel,inti,intj){Node*node=newNode;// Stores parent edges of the state-space treenode->path=path;// Skip for the root nodeif(level!=0){// Add a current edge to the pathnode->path.push_back(make_pair(i,j));}// Copy data from the parent node to the current nodememcpy(node->reducedMatrix,parentMatrix,sizeofnode->reducedMatrix);// Change all entries of row i and column j to INF// skip for the root nodefor(intk=0;level!=0&&k<N;k++){// Set outgoing edges for the city i to INFnode->reducedMatrix[i][k]=INF;// Set incoming edges to city j to INFnode->reducedMatrix[k][j]=INF;}// Set (j, 0) to INF// here start node is 0node->reducedMatrix[j][0]=INF;// Set number of cities visited so farnode->level=level;// Assign current city numbernode->vertex=j;// Return nodereturnnode;}// Function to reduce each row so that // there must be at least one zero in each rowintrowReduction(intreducedMatrix[N][N],introw[N]){// Initialize row array to INFfill_n(row,N,INF);// row[i] contains minimum in row ifor(inti=0;i<N;i++){for(intj=0;j<N;j++){if(reducedMatrix[i][j]<row[i]){row[i]=reducedMatrix[i][j];}}}// Reduce the minimum value from each element // in each rowfor(inti=0;i<N;i++){for(intj=0;j<N;j++){if(reducedMatrix[i][j]!=INF&&row[i]!=INF){reducedMatrix[i][j]-=row[i];}}}return0;}// Function to reduce each column so that // there must be at least one zero in each columnintcolumnReduction(intreducedMatrix[N][N],intcol[N]){// Initialize all elements of array col with INFfill_n(col,N,INF);// col[j] contains minimum in col jfor(inti=0;i<N;i++){for(intj=0;j<N;j++){if(reducedMatrix[i][j]<col[j]){col[j]=reducedMatrix[i][j];}}}// Reduce the minimum value from each element // in each columnfor(inti=0;i<N;i++){for(intj=0;j<N;j++){if(reducedMatrix[i][j]!=INF&&col[j]!=INF){reducedMatrix[i][j]-=col[j];}}}return0;}// Function to get the lower bound on the path // starting at the current minimum nodeintcalculateCost(intreducedMatrix[N][N]){// Initialize cost to 0intcost=0;// Row Reductionintrow[N];rowReduction(reducedMatrix,row);// Column Reductionintcol[N];columnReduction(reducedMatrix,col);// The total expected cost is // the sum of all reductionsfor(inti=0;i<N;i++){cost+=(row[i]!=INT_MAX)?row[i]:0,cost+=(col[i]!=INT_MAX)?col[i]:0;}returncost;}// Function to print list of cities // visited following least costvoidTSPPAthPrint(vector<pair<int,int>>const&list){for(inti=0;i<list.size();i++){cout<<list[i].first+1<<" -> "<<list[i].second+1<<"\n";}}// Comparison object to be used to order the heapstructMin_Heap{booloperator()(constNode*lhs,constNode*rhs)const{returnlhs->cost>rhs->cost;}};// Function to solve the traveling salesman problem // using Branch and Boundintsolve(intCostGraphMatrix[N][N]){// Create a priority queue to store live nodes // of the search treepriority_queue<Node*,vector<Node*>,Min_Heap>pq;vector<pair<int,int>>v;// Create a root node and calculate its cost.// The TSP starts from the first city, i.e., node 0Node*root=newNode(CostGraphMatrix,v,0,-1,0);// Get the lower bound of the path // starting at node 0root->cost=calculateCost(root->reducedMatrix);// Add root to the list of live nodespq.push(root);// Finds a live node with the least cost, // adds its children to the list of live nodes, // and finally deletes it from the listwhile(!pq.empty()){// Find a live node with // the least estimated costNode*min=pq.top();// The found node is deleted from // the list of live nodespq.pop();// i stores the current city numberinti=min->vertex;// If all cities are visitedif(min->level==N-1){// Return to starting citymin->path.push_back(make_pair(i,0));// Print list of cities visitedTSPPAthPrint(min->path);// Return optimal costreturnmin->cost;}// Do for each child of min// (i, j) forms an edge in a space treefor(intj=0;j<N;j++){if(min->reducedMatrix[i][j]!=INF){// Create a child node and // calculate its costNode*child=newNode(min->reducedMatrix,min->path,min->level+1,i,j);child->cost=min->cost+min->reducedMatrix[i][j]+calculateCost(child->reducedMatrix);// Add a child to the list of live nodespq.push(child);}}// Free node as we have already stored edges (i, j)// in vector. So no need for a parent node while// printing the solution.deletemin;}return0;}// Driver codeintmain(){intCostGraphMatrix[N][N]={{INF,10,15,20},{10,INF,35,25},{15,35,INF,30},{20,25,30,INF}};// Function callcout<<"Total cost is "<<solve(CostGraphMatrix);return0;}
Java
importjava.util.*;publicclassMain{// Define the number of vertices and infinity valuestaticfinalintN=4;staticfinalintINF=Integer.MAX_VALUE;// Node class to store each node along with the cost, level, and vertexstaticclassNode{ArrayList<int[]>path=newArrayList<>();int[][]reducedMatrix=newint[N][N];intcost;intvertex;intlevel;}publicstaticvoidmain(String[]args){// Define the cost matrixint[][]CostGraphMatrix={{INF,10,15,20},{10,INF,35,25},{15,35,INF,30},{20,25,30,INF}};// Print the total cost of the tourSystem.out.println("Total cost is "+solve(CostGraphMatrix));}// Function to allocate a new nodestaticNodenewNode(int[][]parentMatrix,ArrayList<int[]>path,intlevel,inti,intj){Nodenode=newNode();node.path=(ArrayList<int[]>)path.clone();// Add this edge to the pathif(level!=0){node.path.add(newint[]{i,j});}// Copy data from parent matrix to current matrixfor(intr=0;r<N;r++){node.reducedMatrix[r]=parentMatrix[r].clone();}// Change all entries of row i and column j to infinity// Also change the entry for vertex k to infinityif(level!=0){for(intk=0;k<N;k++){node.reducedMatrix[i][k]=INF;node.reducedMatrix[k][j]=INF;}node.reducedMatrix[j][0]=INF;}// Update the level of nodenode.level=level;// Update the vertex numbernode.vertex=j;returnnode;}// Function to perform row reductionstaticintrowReduction(int[][]reducedMatrix,int[]row){// Initialize row array to INFArrays.fill(row,INF);// Row[i] contains minimum in row ifor(inti=0;i<N;i++){for(intj=0;j<N;j++){if(reducedMatrix[i][j]<row[i]){row[i]=reducedMatrix[i][j];}}}// Reduce the minimum value from each element in each rowfor(inti=0;i<N;i++){for(intj=0;j<N;j++){if(reducedMatrix[i][j]!=INF&&row[i]!=INF){reducedMatrix[i][j]-=row[i];}}}return0;}// Function to perform column reductionstaticintcolumnReduction(int[][]reducedMatrix,int[]col){// Initialize col array to INFArrays.fill(col,INF);// Col[j] contains minimum in col jfor(inti=0;i<N;i++){for(intj=0;j<N;j++){if(reducedMatrix[i][j]<col[j]){col[j]=reducedMatrix[i][j];}}}// Reduce the minimum value from each element in each columnfor(inti=0;i<N;i++){for(intj=0;j<N;j++){if(reducedMatrix[i][j]!=INF&&col[j]!=INF){reducedMatrix[i][j]-=col[j];}}}return0;}// Function to calculate the cost of the pathstaticintcalculateCost(int[][]reducedMatrix){intcost=0;int[]row=newint[N];rowReduction(reducedMatrix,row);int[]col=newint[N];columnReduction(reducedMatrix,col);// Calculate the cost by adding the reduction valuesfor(inti=0;i<N;i++){cost+=(row[i]!=INF)?row[i]:0;cost+=(col[i]!=INF)?col[i]:0;}returncost;}// Function to print the pathstaticvoidprintPath(ArrayList<int[]>list){for(int[]path:list){System.out.println((path[0]+1)+" -> "+(path[1]+1));}}// Function to solve the TSP problemstaticintsolve(int[][]CostGraphMatrix){// Create a priority queue to store live nodes of the search treePriorityQueue<Node>pq=newPriorityQueue<>(Comparator.comparingInt(node->node.cost));ArrayList<int[]>v=newArrayList<>();// Create a root node and calculate its costNoderoot=newNode(CostGraphMatrix,v,0,-1,0);root.cost=calculateCost(root.reducedMatrix);// Add root to the list of live nodespq.add(root);// Continue until the priority queue becomes emptywhile(!pq.isEmpty()){// Find a live node with the least estimated costNodemin=pq.poll();// Get the vertex numberinti=min.vertex;// If all the cities have been visitedif(min.level==N-1){min.path.add(newint[]{i,0});printPath(min.path);returnmin.cost;}// Generate all the children of minfor(intj=0;j<N;j++){if(min.reducedMatrix[i][j]!=INF){Nodechild=newNode(min.reducedMatrix,min.path,min.level+1,i,j);child.cost=min.cost+min.reducedMatrix[i][j]+calculateCost(child.reducedMatrix);pq.add(child);}}}return0;}}
Python3
importsysfromqueueimportPriorityQueue# Define the number of vertices and infinity valueN=4INF=sys.maxsize# Node class to store each node along with the cost, level, and vertexclassNode:def__init__(self,parentMatrix,path,level,i,j):self.path=path.copy()self.reducedMatrix=[row.copy()forrowinparentMatrix]self.cost=0self.vertex=jself.level=level# Add this edge to the pathiflevel!=0:self.path.append((i,j))# Change all entries of row i and column j to infinity# Also change the entry for vertex k to infinityiflevel!=0:forkinrange(N):self.reducedMatrix[i][k]=INFself.reducedMatrix[k][j]=INFself.reducedMatrix[j][0]=INFdef__lt__(self,other):returnself.cost<other.cost# Function to perform row reductiondefrowReduction(reducedMatrix):row=[INF]*N# Row[i] contains minimum in row iforiinrange(N):forjinrange(N):ifreducedMatrix[i][j]<row[i]:row[i]=reducedMatrix[i][j]# Reduce the minimum value from each element in each rowforiinrange(N):forjinrange(N):ifreducedMatrix[i][j]!=INFandrow[i]!=INF:reducedMatrix[i][j]-=row[i]returnrow# Function to perform column reductiondefcolumnReduction(reducedMatrix):col=[INF]*N# Col[j] contains minimum in col jforiinrange(N):forjinrange(N):ifreducedMatrix[i][j]<col[j]:col[j]=reducedMatrix[i][j]# Reduce the minimum value from each element in each columnforiinrange(N):forjinrange(N):ifreducedMatrix[i][j]!=INFandcol[j]!=INF:reducedMatrix[i][j]-=col[j]returncol# Function to calculate the cost of the pathdefcalculateCost(reducedMatrix):cost=0row=rowReduction(reducedMatrix)col=columnReduction(reducedMatrix)# Calculate the cost by adding the reduction valuesforiinrange(N):cost+=(row[i]ifrow[i]!=INFelse0)cost+=(col[i]ifcol[i]!=INFelse0)returncost# Function to print the pathdefprintPath(path):forpairinpath:print(f"{pair[0]+1} -> {pair[1]+1}")# Function to solve the TSP problemdefsolve(CostGraphMatrix):# Create a priority queue to store live nodes of the search treepq=PriorityQueue()# Create a root node and calculate its costroot=Node(CostGraphMatrix,[],0,-1,0)root.cost=calculateCost(root.reducedMatrix)# Add root to the list of live nodespq.put((root.cost,root))# Continue until the priority queue becomes emptywhilenotpq.empty():# Find a live node with the least estimated costmin=pq.get()[1]# Get the vertex numberi=min.vertex# If all the cities have been visitedifmin.level==N-1:min.path.append((i,0))printPath(min.path)returnmin.cost# Generate all the children of minforjinrange(N):ifmin.reducedMatrix[i][j]!=INF:child=Node(min.reducedMatrix,min.path,min.level+1,i,j)child.cost=min.cost+min.reducedMatrix[i][j]+calculateCost(child.reducedMatrix)pq.put((child.cost,child))return0# Define the cost matrixCostGraphMatrix=[[INF,10,15,20],[10,INF,35,25],[15,35,INF,30],[20,25,30,INF]]# Print the total cost of the tourprint("Total cost is",solve(CostGraphMatrix))
JavaScript
classNode{constructor(){this.path=[];this.reducedMatrix=Array.from({length:N},()=>Array(N).fill(0));this.cost=0;this.vertex=0;this.level=0;}}constINF=Number.MAX_SAFE_INTEGER;constN=4;functionnewNode(parentMatrix,path,level,i,j){constnode=newNode();node.path=[...path];if(level!==0){node.path.push([i,j]);}for(letr=0;r<N;r++){node.reducedMatrix[r]=parentMatrix[r].slice();}if(level!==0){for(letk=0;k<N;k++){node.reducedMatrix[i][k]=INF;node.reducedMatrix[k][j]=INF;}node.reducedMatrix[j][0]=INF;}node.level=level;node.vertex=j;returnnode;}functionrowReduction(reducedMatrix,row){row.fill(INF);for(leti=0;i<N;i++){for(letj=0;j<N;j++){if(reducedMatrix[i][j]<row[i]){row[i]=reducedMatrix[i][j];}}}for(leti=0;i<N;i++){for(letj=0;j<N;j++){if(reducedMatrix[i][j]!==INF&&row[i]!==INF){reducedMatrix[i][j]-=row[i];}}}return0;}functioncolumnReduction(reducedMatrix,col){col.fill(INF);for(leti=0;i<N;i++){for(letj=0;j<N;j++){if(reducedMatrix[i][j]<col[j]){col[j]=reducedMatrix[i][j];}}}for(leti=0;i<N;i++){for(letj=0;j<N;j++){if(reducedMatrix[i][j]!==INF&&col[j]!==INF){reducedMatrix[i][j]-=col[j];}}}return0;}functioncalculateCost(reducedMatrix){letcost=0;constrow=Array(N).fill(0);constcol=Array(N).fill(0);rowReduction(reducedMatrix,row);columnReduction(reducedMatrix,col);for(leti=0;i<N;i++){cost+=row[i]!==INF?row[i]:0;cost+=col[i]!==INF?col[i]:0;}returncost;}functionprintPath(list){for(constpathoflist){console.log(`${path[0]+1} -> ${path[1]+1}`);}}functionsolve(CostGraphMatrix){constpq=newPriorityQueue((a,b)=>a.cost-b.cost);constv=[];constroot=newNode(CostGraphMatrix,v,0,-1,0);root.cost=calculateCost(root.reducedMatrix);pq.enqueue(root);while(!pq.isEmpty()){constmin=pq.dequeue();consti=min.vertex;if(min.level===N-1){min.path.push([i,0]);printPath(min.path);returnmin.cost;}for(letj=0;j<N;j++){if(min.reducedMatrix[i][j]!==INF){constchild=newNode(min.reducedMatrix,min.path,min.level+1,i,j);child.cost=min.cost+min.reducedMatrix[i][j]+calculateCost(child.reducedMatrix);pq.enqueue(child);}}}return0;}classPriorityQueue{constructor(comparator){this.heap=[];this.comparator=comparator||((a,b)=>a-b);}enqueue(element){this.heap.push(element);this.bubbleUp();}dequeue(){constmin=this.heap[0];constlast=this.heap.pop();if(this.heap.length>0){this.heap[0]=last;this.bubbleDown();}returnmin;}isEmpty(){returnthis.heap.length===0;}bubbleUp(){letindex=this.heap.length-1;while(index>0){constparentIndex=Math.floor((index-1)/2);if(this.comparator(this.heap[index],this.heap[parentIndex])>=0){break;}[this.heap[parentIndex],this.heap[index]]=[this.heap[index],this.heap[parentIndex]];index=parentIndex;}}bubbleDown(){letindex=0;while(index<this.heap.length){constleft=2*index+1;constright=2*index+2;letsmallest=index;if(left<this.heap.length&&this.comparator(this.heap[left],this.heap[smallest])<0){smallest=left;}if(right<this.heap.length&&this.comparator(this.heap[right],this.heap[smallest])<0){smallest=right;}if(smallest===index){break;}[this.heap[index],this.heap[smallest]]=[this.heap[smallest],this.heap[index]];index=smallest;}}}constCostGraphMatrix=[[INF,10,15,20],[10,INF,35,25],[15,35,INF,30],[20,25,30,INF]];console.log("Total cost is "+solve(CostGraphMatrix));
Output
1 -> 3
3 -> 4
4 -> 2
2 -> 1
Total cost is 80
Time Complexity: O(2N * N2) where N = number of node/ cities. Space Complexity: O(N2)