Skip to content

Commit fb1bc92

Browse files
authored
Create Bitmask-Dynamic-Programming.md
1 parent c7d5b3b commit fb1bc92

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed

Notes/Bitmask-Dynamic-Programming.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Bitmask Dynamic Programming
2+
3+
## What is Bitmask DP?
4+
5+
Bitmask DP is a type of dynamic programming that uses _bitmasks_, in order to keep track of our current state in a problem.
6+
7+
A bitmask is nothing more than a number that defines which bits are _on_ and _off_, or a binary string representation of the number.
8+
9+
## Traveling Salesman Problem
10+
11+
The traveling salesman problem is a classic algorithmic problem defined as follows: given a list of _N_ cities, as well as the distances between each pair of cities, what is the shortest possible route that visits each city exactly once and returns back to the city that you started from? (_Note_: we can start from any city as long as we return to it)
12+
13+
![img](http://mathworld.wolfram.com/images/eps-gif/TravelingSalesmanProblem_1000.gif)
14+
15+
### Take I - Permutations
16+
17+
We can create a permutation of the _N_ cities to tell us what order we should visit the cities.
18+
19+
For example, if we have _N_ = 4, we could have the permutation {3, 1, 4, 2}, which tells us to visit the cities in the following order: 3 --> 1 --> 4 --> 2 --> 3
20+
21+
For a given _N_, there are _N!_ possible permutations (_N_ choices for the first city, _N-1_ choices for the second city, _N-2_ choices for the third city, etc.)
22+
23+
However, if _N_ > 12, this algorithm will be too slow, so we need to shoot for something better
24+
25+
### Take II - Bitmask DP
26+
27+
Let's use bitmasks to help us with this problem: we'll construct a bitmask of length _N_.
28+
29+
What does the bit at index _k_ represent in the scope of the problem? What does it mean for the bit to be zero? What about one?
30+
- if the bit at index _k_ is zero, then we _have not yet_ visited city _k_
31+
- if the bit at index _k_ is one, then we _have_ visited city _k_
32+
33+
For a given bitmask, we can see which cities we have left to travel to by checking which bits have a value of zero.
34+
35+
We can construct a recursive function to find the answer to this problem:
36+
37+
```java
38+
// The following function will calculate the shortest route that visits all
39+
// unvisited cities in the bitmask and goes back to the starting city
40+
public double solve( int bitmask )
41+
{
42+
if ( dp[ bitmask ] != -1 )
43+
return dp[ bitmask ];
44+
// Handle the usual case
45+
}
46+
```
47+
48+
What are some base cases for this problem? How do we know when we are done?
49+
50+
What does the bitmask look like when we have visited every city?
51+
- 111...111
52+
53+
In this case, we need to return to our starting city, so we'll just return the distance from our current location to the start city, but what is our current location?
54+
55+
Imagine we currently have the bitmask 11111.
56+
57+
This bitmask tells us that we have visited all _N_ = 5 cities and can return home.
58+
59+
However, this bitmasks _does not_ tell us which city we are currently at, so we don't know which distance to return.
60+
61+
This means that in addition to the bitmask, we will need to keep track of the _current location_ (anytime we travel to a city, that city becomes the current location).
62+
63+
```java
64+
// The following function will calculate the shortest route that visits all unvisited
65+
// cities in the bitmask starting from pos, and then goes back to the starting city
66+
public double solve( int bitmask, int pos )
67+
{
68+
if ( dp[ bitmask ][ pos ] != -1 )
69+
return dp[ bitmask ][ pos ];
70+
// Handle the usual case
71+
}
72+
```
73+
74+
If we know that `solve( bitmask, pos )` will give us thge answer to the traveling salesman problem, and we say that we start at city 0, what should our initial function call be?
75+
76+
What is the value of `bitmask`?
77+
- 1 (we visited city 0, so our starting bitmask is 000...0001)
78+
79+
What is the value of `pos`?
80+
- 0
81+
82+
So how do we handle the usual case?
83+
84+
We have a bitmask that tells us which cities we have left to visit, and we know our current position, so which city do we go to next?
85+
- whichever one will minimize the remaining route
86+
87+
To see which city will minimize the value we want, we need to try _all_ possible remaining cities and see how it affects the future routes.
88+
89+
What does trying to visit a city look like?
90+
91+
Let's say that we are visiting some city at index _k_:
92+
93+
```java
94+
int newBitmask = bitmask | ( 1 << k );
95+
double newDist = dist[ pos ][ k ] + solve( newBitmask, k );
96+
```
97+
98+
We need to update our bitmask, marking city _k_ as visited, and then we add the distance from our current loication to city _k_, and then solve the subproblem where we find the shortest route starting at city _k_ and solving for the rest of the cities.
99+
100+
If we do this for each city that hasn't been visited yet, we want to take the minimum `newDist` that we find.
101+
102+
```java
103+
// The following function will calculate the shortest route that visits all unvisited
104+
// cities in the bitmask starting from pos, and then goes back to the starting city
105+
public double solve( int bitmask, int pos )
106+
{
107+
// If we have solved this subproblem previously, return the result that was recorded
108+
if ( dp[ bitmask ][ pos ] != -1 )
109+
return dp[ bitmask ][ pos ];
110+
111+
// If the bitmask is all 1s, we need to return home
112+
if ( bitmask == ( 1 << N ) - 1 )
113+
return dist[ pos ][ 0 ];
114+
115+
// Keep track of the minimum distance we have seen when visiting other cities
116+
double minDistance = 2000000000.0;
117+
118+
// For each city we haven't visited, we are going to try the subproblem that arises from visiting it
119+
for ( int k = 0; k < N; k++ )
120+
{
121+
int res = bitmask & ( 1 << k );
122+
123+
// If we haven't visited the city before, try and visit it
124+
if ( res == 0 )
125+
{
126+
int newBitmask = bitmask | ( 1 << k );
127+
128+
// Get the distance from solving the subproblems
129+
double newDist = dist[ pos ][ k ] + solve( newBitmask, k );
130+
131+
// If newDist is smaller than the current minimum distance, we will override it here
132+
minDistance = Math.min( minDistance, newDist );
133+
}
134+
}
135+
136+
// Set the optimal value of the current subproblem
137+
return dp[ bitmask ][ pos ] = minDistance;
138+
}
139+
```

0 commit comments

Comments
 (0)