使用priority _queue 对Dijkstra进行优化

       对于图的相关算法如最小生成树的Kruskal,Prim算法,最短路径的Dijkstra算法都采用的是贪心算法,而贪心算法最好的辅助工具个人认为就是priority_queue.所以本文将运用priority_queued对算法导论中Dijkstra算法进行优化。对于Dijkstra算法我们先给出算法导论中所给出基本算法实现。

int a[5][5] = {
	       {MAX2,10,MAX2,MAX2,5},
	       {MAX2,MAX2,1,MAX2,2},
	       {MAX2,MAX2,MAX2,4,MAX2},
	       {7,MAX2,6,MAX2,MAX2},
	       {MAX2,3,9,2,MAX2},
	      };
int distant[5] = {MAX2,MAX2,MAX2,MAX2,MAX2};  //标记距离
int visit[5] = {0};     //标记是否内访问
int temp = MAX2;        //MAX2表示不可达

void Dijkstra(int start)
{
	int i,j,k;
	visit[start] = 1;
	distant[start] = 0;

	for(i = 0; i < 5; i++)
	{	if(i!= start)
			distant[i] = a[start][i];
	}
	

	for(i = 0; i < 5; i++)
	{
		temp = MAX2;
		//*************algrithms****对应于算法导论中的EXTRACT-MIN(Q)********************  
		for(j = 0; j < 5; j++)
		{
		
			if(!visit[j] && temp > distant[j])
			{
				temp = distant[j];
				 k = j;
			}
		}
	
		if(temp == MAX2) break;
	
		visit[k] = 1;
		//**********************算法导论中的RELAX(u,v,w)******************************
		for(j = 0; j < 5; j++)
		{
			if(!visit[j] && distant[j] > distant[k] + a[k][j])
				distant[j] = distant[k] + a[k][j];
		}
		//***************************************************
	}
}

上述算法完全按照算法导论中伪代码翻译过来,并且注明了对应关系。下面我们使用优先队列来 优化该算法。完整代码如下(可以说是一种广度搜索算法):

#include<stdio.h>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define raw 5
#define col 5
#define MAX 0x0fffffff

struct node
{       
        int x;       //表示对应的点
        int parent;	//上述代码没有给出具体的路径,在优化代码中我们使用该值存储,x的前去节点
        int cost;   //每次给句cost选出权值最小的点
};

struct cmp
{
        bool operator()(struct node a, struct node b)
        {
                return a.cost > b.cost;
        }
        
};


int  map[raw][col] = {      //算法导论中所给出图的关系矩阵
                        { MAX,  10, MAX,MAX,5},
                        { MAX, MAX, 1,  MAX,2},
                        { MAX,MAX,MAX,  4 ,MAX},
                        {  7, MAX,6, MAX, MAX},
                        {MAX, 3, 9, 2 ,MAX}
                     };
int visit[raw]={0};    //标记该点有没有被访问过
int pre[raw] = {-1,-1,-1,-1,-1};  //展示前趋


void Dijkstra(int start_i, int end_i)
{
        priority_queue<struct node, vector<struct node>, cmp> Queue;//优先队列
        struct node in;
        in.x = start_i;
        in.cost = 0;
        in.parent = -1;
     
        
        Queue.push(in);
        visit[start_i] = 1;
        while(!Queue.empty())
        {
                int i;
                int j;
                struct node out = Queue.top();     //每次弹出cost最小的点
                
                Queue.pop();      //弹出已选的点很重要,不然死循环
                i = out.x;
                pre[out.x] = out.parent;  //标记前趋
                visit[out.x] = 1;		//标记该点已经被 选取
                
                if(out.x == end_i)
                {
                        printf("the min cost is %d\n", out.cost );
                        return ;
                }                        
              //下面代码实现将与i相连得节点入队列相当于算法导论中的松弛
                for(j = 0; j < col; j++)
                {
                        if(map[i][j] != MAX && !visit[j])
                        {       
                               in.x = j;
                           
                               in.parent = i;
                               in.cost = out.cost + map[i][j]; 
                               Queue.push(in);
                        }
                      
                }
         }
}

int main()
{
       Dijkstra(0,3);
       int i;
       i = 3;
       while(pre[i] != -1)
       {        
              printf(" %d pre is:%d\n",i, pre[i]);
              i = pre[i];
       }
}
        

总体来说运用优先队列代码比较简洁,而且有使用堆算法寻找最小的点lgn的复杂度,所以相对于上述算法效率较高。

下面给出一个实例:

有一辆坦克从一个位置到达另一个位置,有些位置需要2s,有些点需要1s先再给出起始点。问最少经过多少s到达目的地。这个可以归结为BFS算法与Dijkstra的结合(毕竟是找最短路径所以Dijkstra肯定合适)。具体大家可以参考下面这篇博客。http://blog.csdn.net/niushuai666/article/details/6674993

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值