UPDATED
After more reading, the solution can be given with the following recurrence relation:
(a) When i = 1 and j = 2, l(i; j) = di
The l(i,j)
recursive function should compute the minimum distance of a bitonic tour i -> 1 -> j
visiting all nodes that are smaller than i
. So, the solution to the initial problem will be l(n,n)
!
Important notes:
we can assume that the nodes are ordered by their x coordinate and labeled accordingly (p1.x < p2.x < p3.x ... < pn.x
). It they weren't ordered, we could sort them in O(nlogn)
time.
l(i,j) = l(j,i)
. The reason is that in the lhs, we have a i ->...-> 1 -> ... -> j
tour which is optimal. However traversing this route backward will give us the same distance, and won't broke bitonic property.
Now the easy cases (note the changes!):
(a) When i = 1 and j = 2, l(i; j) = dist(pi; pj ) = dist(1,2)
Here we have the following tour : 1->1->...->2
. Trivially this is equivalent to the length of the path 1->...->2
. Since points are ordered by their .x
coordinate, there is no point between 1
and 2
, so the straight line connecting them will be the optimal one. ( Choosing any number of other points to visit before 2
would result in a longer path! )
(b) When i < j - 1; l(i; j) = l(i; j - 1) + dist(pj-1; pj)
In this case, j-1
must be on the part of the path 1 -> ... -> j
, because the part i -> ... -> 1
can not contain nodes with an index bigger than i
. Because all nodes in the path 1 -> ... -> j
are in increasing order of index, there can be none between j-1
and j
. So, this is equivalent to the tour: i -> ... -> 1 -> .... -> j-1 -> j
, which is equivalent to l(i,j-1) + dist(pj-1,pj)
!
Anf finally the interesting part comes:
(c) When i = j - 1 or i = j, min 1<=k<i (l(k; i) + dist(pk; pj ))
Here we know that we have to get from i
to 1
, but there is no clue on the backward sweep! The key idea here is that we must think of the node just before j
on our backward route. It may be any of the nodes from 1
to j-1
! Let us assume that this node is k
.
Now we have a tour: i -> ... -> 1 -> .... -> k -> j
, right? The cost of this tour is l(i,k) + dist(pk,pj)
.
Hope you got it.
You will need a 2-dimensional array say BT[1..n][1..n]
. Let i
be the row index, j
be the column index. How should we fill in this table?
In the first row we know BT[1][1] = 0
, BT[1][2] = d(1,2)
, so we have only i,j
indexes left that fall into the (b)
category.
In the remainin rows, we fill the elements from the diagonal till the end.
Here is a sample C++ code (not tested):
void ComputeBitonicTSPCost( const std::vector< std::vector<int> >& dist, int* opt ) {
int n = dist.size();
std::vector< std::vector< int > > BT;
BT.resize(n);
for ( int i = 0; i < n; ++i )
BT.at(i).resize(n);
BT.at(0).at(0) = 0; // p1 to p1 bitonic distance is 0
BT.at(0).at(1) = dist.at(0).at(1); // p1 to p2 bitonic distance is d(2,1)
// fill the first row
for ( int j = 2; j < n; ++j )
BT.at(0).at(j) = BT.at(0).at(j-1) + dist.at(j-1).at(j);
// fill the remaining rows
int temp, min;
for ( int i = 1; i < n; ++i ) {
for ( int j = i; j < n; ++j ) {
BT.at(i).at(j) = -1;
min = std::numeric_limits<int>::max();
if ( i == j || i == j -1 ) {
for( int k = 0; k < i; ++k ) {
temp = BT.at(k).at(i) + dist.at(k).at(j);
min = ( temp < min ) ? temp : min;
}
BT.at(i).at(j) = min;
} else {
BT.at(i).at(j) = BT.at(i).at(j-1) + dist.at(j-1).at(j);
}
}
}
*opt = BT.at(n-1).at(n-1);
}
Okay, the key notions in a dynamic programming solution are:
The essential property of a bitonic tour is that a vertical line in the coordinate system crosses a side of the closed polygon at most twice. So, what is a bitonic tour of exactly two points? Clearly, any two points form a (degenerate) bitonic tour. Three points have two bitonic tours ("clockwise" and "counterclockwise").
Now, how can you pre-compute the various smaller bitonic tours and combine them until you have all points included and still have a bitonic tour?
Okay, you're on the righ track with your update. But now, in a dynamic programming solution, what you do with work it bottom-up: pre-compute and memoize (not "memorize") the optimal subproblems.