优先队列优化Dijkstra算法

//邻接表+优先队列+Dijkstra模版

#include 
#include 
using namespace std;

#define MAXN 101
#define INF 999999

class Graph;  //有向图
class Vnode;  //头结点

class Arcnode  //表结点
{
	friend class Graph;
	friend class Vnode;
private:
	int v;
	int weight;
	Arcnode *next;
public:
	void Arcnode_Init(int e,int w)
	{
		v=e;
		weight=w;
		next=NULL;
	}
};

class Vnode   //头结点
{
	friend class Graph;
private:
	int data;
	Arcnode *firstarc;
public:
	void Vnode_init(int d)
	{
		data=d;
		firstarc=NULL;
	}
};

class DIj_Node  //用于求最短路时候的顶点
{
	friend class Graph;
public:
	int v;
	int dis;
public:
	void Node_init(int dn,int dw)
	{
		v=dn;
		dis=dw;
	}
	friend bool operator < (const DIj_Node &a,const DIj_Node &b)  //是优先队列的队头是最小值
	{
		return (a.dis>b.dis);
	}
};

class Graph
{
private:
	Vnode head[MAXN];  //头结点数组
 	int vexsum;  //顶点总数
	int arcsum;  //边总数
	int dis[MAXN];  //存源点到该顶点的最短路径长度
	int find[MAXN];  //是否已找到最短路径的标志
public:
	void Graph_init(int n)
	{
		vexsum=n;
		for(int i=1;i<=n;i++)
			head[i].Vnode_init(i);
	}

	void Create_Graph(int m)
	{
		int i,s,e,w;
		Arcnode *temp_arc;
		for(i=1;i<=m;i++)
		{
			cout<<"输入第 "<>s>>e>>w;
			temp_arc = new Arcnode;
			temp_arc->Arcnode_Init(e,w);
			temp_arc->next=head[s].firstarc;
			head[s].firstarc=temp_arc;
		}
		arcsum=m;
		cout<<"建图完成"< Q;
		Arcnode *arc;
		int i;
		for(i=1;i<=vexsum;i++)
		{
			dis[i]=INF;
			find[i]=false;
		}
		dis[src]=0;
		temp.Node_init(src,dis[src]);
		Q.push(temp);

		while(!Q.empty())
		{
			first=Q.top();
			Q.pop();
			find[first.v]=true;

			for(arc=head[first.v].firstarc;arc!=NULL;arc=arc->next)
			{
				if(find[arc->v])
					continue;
				next.Node_init(arc->v,first.dis+arc->weight);
				if(next.dis < dis[next.v])
				{
					dis[next.v]=next.dis;
					Q.push(next);
				}
			}
		}
	}

	void Print(int src)
	{
		for(int i=1;i<=vexsum;i++)
		{
			if(i == src)
				continue;
			if(dis[i] == INF)
				cout<>n;
	G.Graph_init(n);
	cout<<"输入边的总数:";
	cin>>m;
	G.Create_Graph(m);
	//cout<<"输入源点和终点:";
	//cin>>src>>des;
	//cout<

测试的数据和邻接矩阵+Dijkstra实现是一样的,这个是以前写的,效率较低,最容易理解的Dijkstra算法。上面的是用优先队列进行优化,以及用邻接表进行存储的实现。

Dijkstra由于是贪心的,每次都找一个距源点最近的点(dmin),然后将该距离定为这个点到源点的最短路径(d[i] ← dmin);但如果存在负权边,那就有可能先通过并不是距源点最近的一个次优点(dmin’),再通过这个负权边 L (L < 0),使得路径之和更小(dmin’ + L < dmin),则 dmin’ + L 成为最短路径,并不是dmin,这样Dijkstra就被囧掉了。比如n = 3,邻接矩阵:

0, 3, 4

3, 0,-2

4,-2, 0

     用Dijkstra求得 d[1,2] = 3,事实上 d[1,2] = 2,就是通过了 1-3-2 使得路径减小。Dijkstra的贪心是建立在边都是正边的基础上,这样,每次往前推进,路径长度都是变大的,如果出现负边,那么先前找到的最短路就不是真正的最短路,比如上边的例子,这个算法也就算废了。


你可能感兴趣的:(Algorithm)