单源最短路——Dijstra

Dijkstra算法:


用途:求单源最短路径,有向图,无向图,边权为正,,正权图上的单源最短路,既从单个源点出发,到所有结点的最短路。


伪代码:


清除所有点的编号

d[0]=0,其他d[i]=INF;

循环n次
{
    在所有没标记的点中找出d最小的结点x;
    标记x
    对于从x结点出发的所有(x,y)
    更新 d[y]=min(d[y],d[x]+w[x][y]);
}

模板一:

Dijkstra1(int x)
{
    memset(vis,0,sizeof(vis));
    for(int i=0; i<=n; i++) dis[i]=INF;
    d[x]=0;
    for(int i=0; i<n; i++)
    {
        int minn=INF;///不要忘记每次都要初始化一下
        int pos;
        for(int j=1; j<=n; j++)
        {
            if(!vis[j]&&minn<dis[j])
            {
                pos=j;
                minn=dis[j];
            }
        }
        vis[pos]=1;
        for(int j=1; j<=n; j++)
        {
            if(dis[j]>dis[pos]+w[pos][j])
            {
                dis[j]=dis[pos]+w[pos][j];
                p[j]=pos;//可以用于记录路径
            }
        }
    }
}
上面程序的时间复杂度为o(n2)
模板二:

稀疏图可以用vector表示,除此之外,还可以用邻接表表示。在这种表示法中,每一个结点i都有一个链表,里面保存着从i出发的所有边,对于无向图来说,每条边都会在邻接表中出现两次,

用数组实现邻接表,首先给每一条边编号,然后用fist保存结点u的第一条边,next表示下一条边,程序如下

Dijkstra2()
{
    int m,n;
    int  first[MAXN];
    int next[MAXN];
    int u[MAXN],e[MAXN],v[MAXN];
    memset(first,-1,sizeof(first));///进行初始化
    int x,y,z;
    for(int i=0; i<n; i++)
    {
        scanf("%d%d%d",&u[i],v[i],e[i]);
        next[i]=fist[u[i]];
        fist[u[i]]=i;
        ///如果是无向图改成
        {
            scanf("%d%d%d",&u[2*i],v[2*i],e[2*i]);
            u[2*i+1]=v[2*i];
            v[2*i+1]=u[2*i];
            e[2*i+1]=e[2*i];
            next[2*i]=fist[u[2*i]];
            fist[u[2*i]]=2*i;
            next[2*i+1]=fist[u[2*i+1]];
            fist[u[2*i+1]]=2*i+1;
        }

    }
}

模板三:

使用结构体储存


struct Edge
{
    int from,to,dist;
    Edge(int u,int v,int d):from(u),to(v),dist(d){}
};
struct HeapNode
{
    int d,u;
    bool operator<(const HeapNode &rhs)const
    {
        return d>rhs.d;
    }
};
struct Dijkstra
{
    int n,m;
    vector<Edge> edges;
    vector<int> G[maxn];
    bool done[maxn];
    int p[maxn];
    int d[maxn];
    void Init(int n)
    {
        n=n;
        for(int i=0;i<=n;i++)
        {
            done[i]=false;
            G[i].clear();
        }
        edges.clear();
    }
    void ADDEdge(int from,int to,int dis)
    {
        edges.push_back(Edge(from,to,dis));
        m=egdes.size();
        G[from].push_back(m-1);
    }
    void dijkstra(int s)
    {
        priority_queue<HeapNode> Q;
        memset(done,0,sizeof(done));
        for(int i=0;i<=n;i++)
            d[i]=INF;
        d[s]=0;
        HeapNode h(0,s);
        Q.push(h);
        while(!Q.empty())
        {
            HeapNode hh=Q.top();
            int u=hh.u;
            Q.pop();
            if(done[u]) continue;
            done[u]=true;

            for(int i=0;i<G[u].size();i++)
            {
                Edge &e=edges[G[u][i]];//注意指针的使用
                if(d[e.to]>d[u]+e.dist)
                {
                    p[e.to]=G[u][i];
                    d[e.to]=d[u]+e.dis;
                    Q.push((HeapNode){d[e.to],e.to});

                }
            }
        }
    }
};




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值