/**
* Q: What is problem we faced ?
*
* A: In our life, there are many problems about pathfinding. Those problems can be simplified as a shorest
* path problem. In a words,we need to find a suitable path to arrive our destination in a map. For examples
* : In Internet, there are many routers work for us to transmit data. They are consist of a huge network.
* It is necessary to find a suitable path between arbitrary two nodes.In addition, this path must be dynamic
* since the huge network is always change.
*/
/**
* Q: How can we solve it ? Any advices ?
*
* A: To solve this problem, I was try to find a method to do it. when I did, I found it is difficult to ensure
* my path is optimal, Although looks like. There are still possible exist a path that is more shorter than
* I‘s. Now, the problem is how can we ensure a path is optimal. That is not easy. But Dijkstra has been
* introduced a amazing method. Usually, we explore a new thing by analyze it basic principles first. But
* that is not always suitable.For this algorithm, we will try to explore it from the outside to the inside.
* First at all, we simple explain how we can get a shorest path. Then we will demonstrate it.
*/
/**
* Q: How does Dijkstrate Algorithm work ?
*
* workflow:
* 1). label the start point as visited and others as unvisit.
* 2). obviously, the distance from the start point to the start point is 0.
* 3). compute the distance between the start point and it‘s neighbor nodes.
* 4). choice the nearest node, label it as visited. and we can ensure it‘s path is shorest path.
* 5). compute the distance between start point and all of nodes which have at least one visited node as
* neighbor.
* 6). choice the nearest node, label it as visited.
* 7). return step(5) untill the new nearest node is destination.
* When we find destination, all of nodes,which has been labeled as visited , has been get the shorest path.
* Here has a Animation about this:
*
http://optlab-server.sce.carleton.ca/POAnimations2007/DijkstrasAlgo.html
*/
/**
* Q: Why does it work ?
*
* A: recall the steps above, there are two steps is suspicious. One,when we want to find the nearest node, we
* always check the neighbor node of visited node.But why the nearest node is reside in the neighbor nodes ?
* Two, when we found a "nearest node", why we can ensure a path is optimal by find nearest node ?
*/
/**
* Q: why the nearest node is reside in the neighbor nodes ?
*
* A: First at all, we declare a words: nearest node, that is a node which have a nearest distance except for visited node.
*
* build three set: SV( set of visited nodes), SU( set of unvisited nodes), and NN(set of neighbor nodes). SV
* is used to contain all of nodes which has been visited. SU is used to contatin nodes which is unvisited.
* NN is set of nodes which is neighbor with at least one visited node. Assume that:
* s -- start point
* x -- a element of NN
* y -- a element of SV
* z -- a element of SU
* if we want to find a path to z.( s->...->z). The path must contain a node of NN. That means
* s->...->z.
* must belong to
* s->...->x ->...->z
* we can always know
* L(s->...->x) < L(s->...->x ->...->z) = L(s->...->z)
* So whatever we choice unvisited node and path, we can still find a more shorter path value in the
* neighbor node.
*/
/**
* Q: why we can ensure a path is optimal by find nearest node ?
*
* A: As we analysis above, the nearest node must be the neighbor of a visited node.
* Now, at the example above ,Image we has been found a nearest node x, we can get this conclusion:
* L(s->...->x) = Min{ s->...->x} ---expr1
* That‘s means there is no path have a more shorter distance than L(s->...->x).
*
* If that is wrong, there are another path is more shorter. That must be
* L(s->...->x0->...->z->...->x) < L(s->...->x)
* (x0 is belong to NN, but not same with x)
* That‘s means
* L(s->...->x0) < L(s->...->x0->...->z->...->x) < L(s->...->x)
* !!!!!!
* L(s->...->x0) < L(s->...->x)
* that is impossible.
* So if we can find a nearest node ,then we can ensure the path is optimal.
*/
/**
* Here is an example
*/
#include <stdio.h>
/*
* the distance of unneighborly nodes
*/
#define UNRN 99
/*
* used to index to a array,based on 0
*/
typedef int INDEX;
/*
* there are two status for a node.
*/
enum VISITSTAT{
L_UNVISIT,
L_VISIT,
L_INVALID,
};
class Dijkstra {
public:
Dijkstra( int map[], int e_num, int unre);
~Dijkstra( );
bool set( int start, int target);
bool work( );
/*
* show the value of distance of nodes. when a node has been labeled as visited.
* this value represent the minimum distance.
*/
bool show();
/*
* show the path from start point to destination.
*/
bool showPath( );
private:
/*
* when we label a new node as visited, we need to update the distance of
* neighbor node.
*/
bool _UpdateRelDistanceTable();
/*
* used to find the nearest node when we had update the distance value of
* neighbor node.
*/
bool _GetNextNearest( INDEX &ind);
int _mapNode( INDEX x, INDEX y);
bool _mapLabel( INDEX x);
bool _travel( INDEX cur);
/**
* To a node, three types of information is necessary:
* 1). the relationship between this node with other nodes. Whether their are neighbor.
* what is the distance between two nodes.
* 2). the status of a node. Whether a node has been visited.
* 3). the distance between the start node with the other nodes.
*/
//relationship between nodes
int *map;
//status of those nodes
VISITSTAT *ele_stat;
//the distance
int *ele_relds;
//the number of the elements
int ele_num;
//start point
INDEX start;
//end point
INDEX target;
//the value of unrelated node.
int unre;
};
Dijkstra::Dijkstra( int map[], int e_num, int unre)
{
this->map = map;
this->ele_relds = new int[ e_num];
this->ele_stat = new VISITSTAT[e_num];
this->ele_num = e_num;
this->start = 0;
this->target = 0;
this->unre = unre;
/*
* label all of nodes as unvisited
*/
for( int i=0; i<e_num; i++)
this->ele_stat[i] = L_UNVISIT;
/*
* initialize the distance as unreachable
*/
for( int i=0; i <e_num; i++)
this->ele_relds[i] = unre;
}
Dijkstra::~Dijkstra( )
{ }
/**
* Logically, a map should be a two-dimensional array. But we can only build a
* one-dimensional array because of some reasons. So, for convenience,we define
* a function used to help us access the map.
*/
int Dijkstra::_mapNode( INDEX x, INDEX y)
{
return this->map[ this->ele_num* x + y];
}
bool Dijkstra::_mapLabel( INDEX x)
{
if( (x<0)
|| (x>=this->ele_num) )
return false;
this->ele_stat[x] = L_VISIT;
return true;
}
bool Dijkstra::set( INDEX start, INDEX target)
{
this->start = start;
this->target = target;
return true;
}
/**
* the core function, used to realize the algorithm.
*/
bool Dijkstra::work( )
{
/*
* first at all, we label the start node as visited and initialize the distance between this node
* with the start point. Obviously, it is 0.
*/
INDEX cur = this->start;
this->ele_relds[cur] = 0;
this->_mapLabel( cur);
/*
* we compute the distance of neighbor nodes and find the nearest node periodically.
* Untill find the nearest node is destination, we get the shortest path to the destination.
*/
do
{
//update the related distance of visited node
this->_UpdateRelDistanceTable( );
//get the nearest node and label it as visited
if( !this->_GetNextNearest( cur))
{
return false;
}
this->_mapLabel( cur);
} while( cur!=this->target);
return true;
}
bool Dijkstra::show()
{
INDEX i;
printf(" %d-->%d\n", this->start, this->target);
for( i=0; i<this->ele_num; i++)
{
printf("[%d] %4d\n", this->ele_stat, this->ele_relds[i]);
}
return true;
}
/**
* Actually, we didn't save information about the shorest path. But ,with the help of the
* information of shorest distance, we can still deduce the right path reversely.
*/
bool Dijkstra::showPath( )
{
INDEX cur = this->target;
this->_travel( cur);
return true;
}
/**
* As we all know, all of the shorest distance of visited nodes is resolved. So
* if we want to find the right path of a node, we just need to ensure :
* the shorest distance of current node is equal to the sum of the shorest distance
* of neighbor node and its' path.
*
*/
bool Dijkstra::_travel( INDEX cur)
{
if( cur==this->start)
{
printf("%d\n", cur);
return false;
}
printf(" %d->", cur);
INDEX i;
for( i=0; i<this->ele_num; i++)
{
//find neighbor
if( this->_mapNode( cur, i)!=this->unre )
{
//find right path
if((i!=cur)
&&(this->ele_relds[cur]==this->ele_relds[i] + this->_mapNode( cur, i)) )
{
this->_travel( i);
}
}
}
return true;
}
bool Dijkstra::_UpdateRelDistanceTable( )
{
INDEX i;
for( i=0; i<this->ele_num; i++)
{
//find those nodes visited
if( this->ele_stat[i] == L_VISIT)
{
INDEX j;
for( j=0; j<this->ele_num; j++)
{
//find those nodes which is neighboor to the visited node and unvisited
if( (this->_mapNode( i, j)!=this->unre)
&&(this->ele_stat[j])==L_UNVISIT )
{
//compute related distance
int rel_ds = this->ele_relds[i]+ this->_mapNode( i, j);
//update related distance
if( rel_ds<this->ele_relds[j] )
this->ele_relds[j] = rel_ds;
}
}
}
}
return true;
}
bool Dijkstra::_GetNextNearest( INDEX &ind)
{
INDEX min = -1;
INDEX i;
for( i=0; i<this->ele_num; i++)
{
//find those nodes visited
if( this->ele_stat[i]==L_VISIT)
{
INDEX j;
for( j=0; j<this->ele_num; j++)
{
//find nodes which is neighboor and unvisited
if( (this->_mapNode( i, j)!=this->unre)
&&(this->ele_stat[ j]==L_UNVISIT) )
{
if( ( min == -1)
||(this->ele_relds[j]<this->ele_relds[min]))
{
min = j;
}
}
}
}
}
ind = min;
return ind==-1?false:true;
}
#define E_NUM 8
// O A B C D E F T
static int Map[ E_NUM*E_NUM] = {
/* O*/ 0, 2, 5, 4, UNRN, UNRN, UNRN, UNRN,
/* A*/ 2, 0, 2, UNRN, UNRN, UNRN, 12, UNRN,
/* B*/ 5, 2, 0, 1, 4, UNRN, UNRN, UNRN,
/* C*/ 4, UNRN, 1, 0, UNRN, 4, UNRN, UNRN,
/* D*/ UNRN, UNRN, 4, UNRN, 0, 1, UNRN, 5,
/* E*/ UNRN, UNRN, UNRN, 4, 1, 0, UNRN, 7,
/* F*/ UNRN, 12, UNRN, UNRN,UNRN, UNRN, 0, 3,
/* T*/ UNRN, UNRN, UNRN, UNRN,5, 7, 3, 0,
};
static int UnreNode = UNRN;
int main()
{
Dijkstra map( Map, E_NUM, UnreNode);
map.set( 0, 7);
map.work( );
map.show();
map.showPath();
return 0;
}
原文地址:http://blog.csdn.net/u012301943/article/details/37991929