Bitmasking and Dynamic Programming | Travelling Salesman Problem
Last Updated : 26 Nov, 2024
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report
Given a 2D grid of characters representing a town where '*' represents the houses, 'x' represents the blockage, '.' represents the vacant street area and 'o' represents the starting position. The task is to determine the minimum distance to be moved to visit all the houses if possible otherwise return -1. We can only move to adjacent cells that share exactly 1 edge with the current cell and we can visit a house twice or more.
If we treat each house as a node, the problem can be viewed as finding theminimum steps required to visit all nodes. In this problem, each house is a node in a graph, and we need to find the shortest path to visit all of them. The key challenge is that the same node (house) can be visited multiple times, but only if it allows us to visit more houses. Simply revisiting a node with the same number of visited houses is redundant.
Since we are working with a grid and the cost to move to an adjacent cell is always one, we can use BFS to find the shortest path. However, since we can move in all four directions, the same node might be revisited multiple times. This means we cannot simply use a visited array as in standard BFS. Instead, we need a way to uniquely represent each state. To address this, we assign each house a unique houseId. Once we have the houseId, we can track house visits by setting the corresponding bits in a bitmask. The bitmask represents the set of visited houses, and the coordinates (x, y) track the current position. This allows us to mark each state uniquely. Revisiting a node is only valid if it results in a different set of visited houses.
C++
// C++ program to find minimum step required to// visit all houses.#include<bits/stdc++.h>usingnamespacestd;intfindMinSteps(vector<vector<char>>&mat){intn=mat.size();intm=mat[0].size();// Transforming the grid: assign unique IDs to// houses and mark obstacles Grid to store houses and obstaclesvector<vector<int>>grid(n,vector<int>(m,0));inthouseId=0;intstartX=0,startY=0;// Process the grid and assign unique IDs to houses, // and find starting positionfor(inti=0;i<n;i++){for(intj=0;j<m;j++){if(mat[i][j]=='.'){// Open cell, marked as 0grid[i][j]=0;}elseif(mat[i][j]=='*'){// Assign unique ID to each housegrid[i][j]=houseId++;}elseif(mat[i][j]=='o'){// Record starting row and columnstartX=i;startY=j;}else{// Mark obstacles as -1grid[i][j]=-1;}}}// If there are no houses to visit, return 0if(houseId==0)return0;// BFS setup: Visited array and queuevector<vector<vector<int>>>vis(1<<houseId,vector<vector<int>>(n,vector<int>(m,0)));// BFS queue to store (visitedMask, x, y)queue<vector<int>>q;// Mark the starting position as visitedvis[0][startX][startY]=1;// Push the initial state (0 mask, startX, startY)q.push({0,startX,startY});// Counter for the number of stepsintsteps=0;// Directions for BFS traversal: right, left, down, upintdx[]={0,0,1,-1};intdy[]={1,-1,0,0};// BFS loopwhile(!q.empty()){intqSize=q.size();for(intidx=0;idx<qSize;idx++){autocurr=q.front();q.pop();// Mask of visited housesintmask=curr[0];// Current x positionintx=curr[1];// Current y positioninty=curr[2];// If all houses are visited, return// the steps takenif(mask==(1<<houseId)-1){returnsteps;}// Explore all possible moves (right, left, down, up)for(intk=0;k<4;k++){// Calculate new x and y position.intnewX=x+dx[k];intnewY=y+dy[k];// Check boundaries and ensure it's not a blocked cellif(newX>=0&&newX<n&&newY>=0&&newY<m&&grid[newX][newY]!=-1){if(mat[newX][newY]=='*'){// If it's a house, update the visited maskintnewMask=mask|(1<<grid[newX][newY]);// If the new state is already visited, continueif(vis[newMask][newX][newY])continue;// Mark the new state as visitedvis[newMask][newX][newY]=1;// Push the new state to the queueq.push({newMask,newX,newY});}else{// If it's a normal cell, continue without// updating the maskif(vis[mask][newX][newY])continue;vis[mask][newX][newY]=1;q.push({mask,newX,newY});}}}}// Increment step count after processing all// states at the current levelsteps++;}// If unable to visit all houses, return -1return-1;}intmain(){vector<vector<char>>mat={{'.','.','.','.','.','.','.'},{'.','o','.','.','.','*','.'},{'.','.','.','.','.','.','.'},{'.','*','.','.','.','*','.'},{'.','.','.','.','.','.','.'}};intres=findMinSteps(mat);cout<<res<<endl;return0;}
Java
// Java program to find minimum step required// to visit all houses.importjava.util.*;classGfG{staticintfindMinSteps(char[][]mat){intn=mat.length;intm=mat[0].length;// Transforming the grid: assign unique IDs to// houses and mark obstacles Grid to store houses// and obstaclesint[][]grid=newint[n][m];inthouseId=0;intstartX=0,startY=0;// Process the grid and assign unique IDs to houses,// and find starting positionfor(inti=0;i<n;i++){for(intj=0;j<m;j++){if(mat[i][j]=='.'){// Open cell, marked as 0grid[i][j]=0;}elseif(mat[i][j]=='*'){// Assign unique ID to each housegrid[i][j]=houseId++;}elseif(mat[i][j]=='o'){// Record starting row and columnstartX=i;startY=j;}else{// Mark obstacles as -1grid[i][j]=-1;}}}// If there are no houses to visit, return 0if(houseId==0)return0;// BFS setup: Visited array and queueboolean[][][]vis=newboolean[1<<houseId][n][m];// BFS queue to store (visitedMask, x, y)Queue<int[]>q=newLinkedList<>();// Mark the starting position as visitedvis[0][startX][startY]=true;// Push the initial state (0 mask, startX, startY)q.add(newint[]{0,startX,startY});// Counter for the number of stepsintsteps=0;// Directions for BFS traversal: right, left, down,// upint[]dx={0,0,1,-1};int[]dy={1,-1,0,0};// BFS loopwhile(!q.isEmpty()){intqSize=q.size();for(intidx=0;idx<qSize;idx++){int[]curr=q.poll();// Mask of visited housesintmask=curr[0];// Current x positionintx=curr[1];// Current y positioninty=curr[2];// If all houses are visited, return the// steps takenif(mask==(1<<houseId)-1){returnsteps;}// Explore all possible moves (right, left,// down, up)for(intk=0;k<4;k++){// Calculate new x and y position.intnewX=x+dx[k];intnewY=y+dy[k];// Check boundaries and ensure it's not// a blocked cellif(newX>=0&&newX<n&&newY>=0&&newY<m&&grid[newX][newY]!=-1){if(mat[newX][newY]=='*'){// If it's a house, update the// visited maskintnewMask=mask|(1<<grid[newX][newY]);// If the new state is already// visited, continueif(vis[newMask][newX][newY])continue;// Mark the new state as visitedvis[newMask][newX][newY]=true;// Push the new state to the// queueq.add(newint[]{newMask,newX,newY});}else{// If it's a normal cell,// continue without updating the// maskif(vis[mask][newX][newY])continue;vis[mask][newX][newY]=true;q.add(newint[]{mask,newX,newY});}}}}// Increment step count after processing all// states at the current levelsteps++;}// If unable to visit all houses, return -1return-1;}publicstaticvoidmain(String[]args){char[][]mat={{'.','.','.','.','.','.','.'},{'.','o','.','.','.','*','.'},{'.','.','.','.','.','.','.'},{'.','*','.','.','.','*','.'},{'.','.','.','.','.','.','.'}};intres=findMinSteps(mat);System.out.println(res);}}
Python
# Python program to find minimum step required # to visit all houses.fromcollectionsimportdequedeffindMinSteps(mat):n=len(mat)m=len(mat[0])# Transforming the grid: assign unique IDs to# houses and mark obstacles Grid to store houses and obstaclesgrid=[[0]*mfor_inrange(n)]houseId=0startX=startY=0# Process the grid and assign unique IDs to houses, # and find starting positionforiinrange(n):forjinrange(m):ifmat[i][j]=='.':# Open cell, marked as 0grid[i][j]=0elifmat[i][j]=='*':# Assign unique ID to each housegrid[i][j]=houseIdhouseId+=1elifmat[i][j]=='o':# Record starting row and columnstartX=istartY=jelse:# Mark obstacles as -1grid[i][j]=-1# If there are no houses to visit, return 0ifhouseId==0:return0# BFS setup: Visited array and queuevis=[[[False]*mfor_inrange(n)]for_inrange(1<<houseId)]# BFS queue to store (visitedMask, x, y)q=deque()# Mark the starting position as visitedvis[0][startX][startY]=True# Push the initial state (0 mask, startX, startY)q.append([0,startX,startY])# Counter for the number of stepssteps=0# Directions for BFS traversal: right, left, down, updx=[0,0,1,-1]dy=[1,-1,0,0]# BFS loopwhileq:qSize=len(q)for_inrange(qSize):curr=q.popleft()# Mask of visited housesmask=curr[0]# Current x positionx=curr[1]# Current y positiony=curr[2]# If all houses are visited, return the# steps takenifmask==(1<<houseId)-1:returnsteps# Explore all possible moves (right, left, down, up)forkinrange(4):# Calculate new x and y position.newX=x+dx[k]newY=y+dy[k]# Check boundaries and ensure it's not a blocked cellif0<=newX<nand0<=newY<mandgrid[newX][newY]!=-1:ifmat[newX][newY]=='*':# If it's a house, update the visited masknewMask=mask|(1<<grid[newX][newY])# If the new state is already visited, continueifvis[newMask][newX][newY]:continue# Mark the new state as visitedvis[newMask][newX][newY]=True# Push the new state to the queueq.append([newMask,newX,newY])else:# If it's a normal cell, continue without# updating the maskifvis[mask][newX][newY]:continuevis[mask][newX][newY]=Trueq.append([mask,newX,newY])# Increment step count after processing all states# at the current levelsteps+=1# If unable to visit all houses,# return -1return-1mat=[['.','.','.','.','.','.','.'],['.','o','.','.','.','*','.'],['.','.','.','.','.','.','.'],['.','*','.','.','.','*','.'],['.','.','.','.','.','.','.']]res=findMinSteps(mat)print(res)
C#
// C# program to find minimum step required// to visit all houses.usingSystem;usingSystem.Collections.Generic;classGfG{staticintfindMinSteps(char[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);// Transforming the grid: assign unique IDs to// houses and mark obstacles Grid to store houses// and obstaclesint[,]grid=newint[n,m];inthouseId=0;intstartX=0,startY=0;// Process the grid and assign unique IDs to houses,// and find starting positionfor(inti=0;i<n;i++){for(intj=0;j<m;j++){if(mat[i,j]=='.'){// Open cell, marked as 0grid[i,j]=0;}elseif(mat[i,j]=='*'){// Assign unique ID to each housegrid[i,j]=houseId;houseId++;}elseif(mat[i,j]=='o'){// Record starting row and columnstartX=i;startY=j;}else{// Mark obstacles as -1grid[i,j]=-1;}}}// If there are no houses to visit, return 0if(houseId==0)return0;// BFS setup: Visited array and queuebool[,,]vis=newbool[1<<houseId,n,m];// BFS queue to store (visitedMask, x, y)Queue<int[]>q=newQueue<int[]>();// Mark the starting position as visitedvis[0,startX,startY]=true;// Push the initial state (0 mask, startX, startY)q.Enqueue(newint[]{0,startX,startY});// Counter for the number of stepsintsteps=0;// Directions for BFS traversal: right, left, down,// upint[]dx={0,0,1,-1};int[]dy={1,-1,0,0};// BFS loopwhile(q.Count>0){intqSize=q.Count;for(intidx=0;idx<qSize;idx++){int[]curr=q.Dequeue();// Mask of visited housesintmask=curr[0];// Current x positionintx=curr[1];// Current y positioninty=curr[2];// If all houses are visited, return the// steps takenif(mask==(1<<houseId)-1){returnsteps;}// Explore all possible moves (right, left,// down, up)for(intk=0;k<4;k++){// Calculate new x and y position.intnewX=x+dx[k];intnewY=y+dy[k];// Check boundaries and ensure it's not// a blocked cellif(newX>=0&&newX<n&&newY>=0&&newY<m&&grid[newX,newY]!=-1){if(mat[newX,newY]=='*'){// If it's a house, update the// visited maskintnewMask=mask|(1<<grid[newX,newY]);// If the new state is already// visited, continueif(vis[newMask,newX,newY])continue;// Mark the new state as visitedvis[newMask,newX,newY]=true;// Push the new state to the// queueq.Enqueue(newint[]{newMask,newX,newY});}else{// If it's a normal cell,// continue without updating the// maskif(vis[mask,newX,newY])continue;vis[mask,newX,newY]=true;q.Enqueue(newint[]{mask,newX,newY});}}}}// Increment step count after processing all// states at the current levelsteps++;}// If unable to visit all houses, return -1return-1;}staticvoidMain(string[]args){char[,]mat={{'.','.','.','.','.','.','.'},{'.','o','.','.','.','*','.'},{'.','.','.','.','.','.','.'},{'.','*','.','.','.','*','.'},{'.','.','.','.','.','.','.'}};intres=findMinSteps(mat);Console.WriteLine(res);}}
JavaScript
// JavaScript program to find minimum step required// to visit all houses.functionfindMinSteps(mat){constn=mat.length;constm=mat[0].length;// Transforming the grid: assign unique IDs to houses// and mark obstacles Grid to store houses and obstaclesconstgrid=Array.from({length:n},()=>Array(m).fill(0));lethouseId=0;letstartX=0,startY=0;// Process the grid and assign unique IDs to houses, and// find starting positionfor(leti=0;i<n;i++){for(letj=0;j<m;j++){if(mat[i][j]==="."){// Open cell, marked as 0grid[i][j]=0;}elseif(mat[i][j]==="*"){// Assign unique ID to each housegrid[i][j]=houseId;houseId++;}elseif(mat[i][j]==="o"){// Record starting row and columnstartX=i;startY=j;}else{// Mark obstacles as -1grid[i][j]=-1;}}}// If there are no houses to visit, return 0if(houseId===0)return0;// BFS setup: Visited array and queueconstvis=Array.from({length:1<<houseId},()=>Array.from({length:n},()=>Array(m).fill(false)));// BFS queue to store (visitedMask, x, y)constqueue=[];// Mark the starting position as visitedvis[0][startX][startY]=true;// Push the initial state (0 mask, startX, startY)queue.push([0,startX,startY]);// Counter for the number of stepsletsteps=0;// Directions for BFS traversal: right, left, down, upconstdx=[0,0,1,-1];constdy=[1,-1,0,0];// BFS loopwhile(queue.length>0){constqSize=queue.length;for(letidx=0;idx<qSize;idx++){const[mask,x,y]=queue.shift();// If all houses are visited, return the steps// takenif(mask===(1<<houseId)-1){returnsteps;}// Explore all possible moves (right, left,// down, up)for(letk=0;k<4;k++){// Calculate new x and y position.constnewX=x+dx[k];constnewY=y+dy[k];// Check boundaries and ensure it's not a// blocked cellif(newX>=0&&newX<n&&newY>=0&&newY<m&&grid[newX][newY]!==-1){if(mat[newX][newY]==="*"){// If it's a house, update the// visited maskconstnewMask=mask|(1<<grid[newX][newY]);// If the new state is already// visited, continueif(vis[newMask][newX][newY])continue;// Mark the new state as visitedvis[newMask][newX][newY]=true;// Push the new state to the queuequeue.push([newMask,newX,newY]);}else{// If it's a normal cell, continue// without updating the maskif(vis[mask][newX][newY])continue;vis[mask][newX][newY]=true;queue.push([mask,newX,newY]);}}}}// Increment step count after processing all states// at the current levelsteps++;}// If unable to visit all houses, return -1return-1;}constmat=[[".",".",".",".",".",".","."],[".","o",".",".",".","*","."],[".",".",".",".",".",".","."],[".","*",".",".",".","*","."],[".",".",".",".",".",".","."]];constres=findMinSteps(mat);console.log(res);
Output
8
Time Complexity: O(2^totalHouse*n*m) where n and m are number of rows and columns of matrix and totalHouse is the number of house in matrix. Auxilary Space: O(2^totalHouse*n*m)
We use cookies to ensure you have the best browsing experience on our website. By using our site, you
acknowledge that you have read and understood our
Cookie Policy &
Privacy Policy
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.