图—单源最短路径算法(二)Dijksta算法

Dijksta算法:

Dijksta算法相比于Bellman-Ford算法,效率提高了许多,但是不能解决带有负权值的图,所以要根据具体问题采取相应的算法,即有负权值的图只能用Bellman-Ford算法,如果权值是非负的,那么我们就选择Dijksta算法,效率高嘛。

分析:

1.找到最短距离已经确定的顶点,从它出发更新相邻顶点的最短距离。
2.此后不需要再关心1中的“最短距离已经确定的顶点”。
在最开始的时候,只有起点的最短距离是确定的,而在尚未使用过的顶点中,距离d[i]最小的顶点就是最短距离已经确定的顶点。


代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1000+10;
const int INF =  99999999;
int cost[maxn][maxn];//cost[u][v]表示边e=(u,v)的权值 
int d[maxn];         //顶点s出发的最短距离
bool used[maxn];     //已经使用过的图
int V,E;             //顶点数,边数 
/*初始化*/
void init()
{
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            if (i == j) {
                cost[i][j] = 0;
            }
            else {
                cost[i][j] = INF;
            }
        }
    }
}

void dijkstra(int s)
{
    for(int i=0; i<V; i++)
    {
        d[i] = INF;
        used[i] = false;
    }
    d[s] = 0;
    while(true)
    {
        int v = -1;
        //从尚未使用过的顶点中选择一个距离最小的顶点
        for(int u = 0; u < V; u++)
        {
            if(!used[u] && (v == -1 || d[u] < d[v])) v = u;
        }
        if(v == -1) break; //所有边都访问过,则退出
        used[v] = true;
        for(int u = 0; u < V; u++)
        {
            d[u] = min(d[u], d[v] + cost[v][u]);
        }
    }   
} 

int main()
{
    scanf("%d%d",&V,&E);
    int s,t,c;
    init();
    for(int i=0;i<E;i++)
    {
        scanf("%d%d%d",&s,&t,&c);
        cost[s][t] = cost[t][s] = c;
    }
    dijkstra(0);
    for(int i=0;i<V;i++)
    printf("%d ",d[i]);
    return 0;
}

优化

下面需要优化的是数值的插入和取出最小值两个操作。使用堆就可以了。把每个顶点当前的最短距离用堆来维护,在更新最短距离时,把对应的元素忘根的方向移动以满足堆的性质。每次从堆中取出的最小值就是下一次要使用的顶点。下面使用STL中的priority_queue来实现,优先队列通过优先级的先后来排队,这样在每次更新时往堆里插入当前最短距离和顶点的值。

#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 1000;
const int INF = 99999999;
struct edge{
    int to,cost;
    edge(int to, int cost) : to(to), cost(cost){}
};
typedef pair<int,int> P;//first是最短路径,second是顶点的编号 
int d[maxn];
int V,E;
vector<edge> G[maxn];

void dijkstra(int s)
{
    priority_queue<P,vector<P>,greater<P> > q;
    fill(d, d + V, INF);
    d[s] = 0;
    q.push(P(0,s));

    while(!q.empty())
    {
        P p = q.top(); q.pop();
        int v = p.second;
        if(d[v] < p.first) continue;
        for(int i=0; i<G[v].size(); i++)
        {
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.cost)
            {
                d[e.to] = d[v] + e.cost;
                q.push(P(d[e.to],e.to)); 
            }
        }
    }
 } 
int main()
{
    scanf("%d%d",&V,&E);
    int s,t,c;
    for(int i=0;i<E;i++)
    {
        scanf("%d%d%d",&s,&t,&c);
        G[s].push_back(edge(t,c));
    }
    dijkstra(0);
    for(int i=0; i<V; i++)
    {
        printf("%d ",d[i]);
    }
    return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值