现在的位置: 首页 > 综合 > 正文

Dijstra算法

2018年02月21日 ⁄ 综合 ⁄ 共 2251字 ⁄ 字号 评论关闭

Dijstra算法求单源点最短路,复杂度为O(n*n+m),用优先级队列优化后为O(n*logn).

首先建立一个集合S,当所有的点都在集合S中时,则算法结束.

1.找不在S集合中的点与s有最短距离的点m

2.更新.dis[m]=min(dis[m]+map[m][i],dis[i]),pre[i]=m;

这里写了下不完全的代码。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
void Dijstra()
{
    //初始化
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        if(i==j)
        map[i][j]=0;
        else
        map[i][j]=INF;
    }
    init();//输入
    
    bool S[maxn];//标记S集合的点
    for(int i=1;i<=n;i++)//初始化每个点的最初距离,和前驱
    {
        dis[i]=map[s][i];//距离为最初值
        S[i]=0;//最初都不在S集合中
        if(dis[i]==INF)
        pre[i]=-1;
        else
        pre[i]=s;
    }
    S[s]=1;
    dis[s]=0;
    
    for(int j=2;j<=n;j++)//只要遍历n-1次,只有n-1个点
    {
        //找不在S集合中的点与s的最短距离
        int mindis=INF;
        int m=s;
        for(int i=1;i<=n;i++)
        {
            if(!S[i]&&dis[i]!=INF)//i不在S集合中,dis[i]不为INF
            {
                if(dis[i]<mindis)
                {
                    mindis=dis[i];
                    m=i;
                }
            }
        }
        //mindis,m
        S[m]=1;
        //更新距离
        for(int i=1;i<=n;i++)
        {
            if(map[m][i]<INF&&!S[i])
            {
                if(dis[m]+map[m][i]<dis[i])
                {
                    dis[i]=dis[m]+map[m][i];
                    pre[i]=m;
                }
            }
        }
    }
    //dis[e],path
}
void Printpath()
{
    stack<int> q;
    q.push(e);
    int u=e;
    while(u!=s)
    {
        q.push(u);
        u=pre[u];
    }
    cout<<s;
    while(!empty())
    {
        cout<<' '<<q.top();
        q.pop();
    }
    cout<<endl;
}
int main()
{
    init();
    Dijstra();
    Printpath();
	return 0;
}

用优先级队列优化后复杂度为O(n*logn)的代码。

#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
using namespace std;
int n,m;
struct edg
{
    friend bool operator<(edg x,edg y)
    return x.l<y.l;
    int v,l;
}
void init()
{
    cin>>n>>m;
    int u,v,c;
    for(int i=0;i<m;i++)
    {
        cin>>u>>v>>c;
        map[u][v]=c;
        map[v][u]=c;
    }
}
void Dijstra()
{
    priority_queue<edg>p;
    //初始化
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        if(i==j)
        map[i][j]=0;
        else
        map[i][j]=INF;
    }
    init();//输入
    
    bool S[maxn];//标记S集合的点
    for(int i=1;i<=n;i++)//初始化每个点的最初距离,和前驱
    {
        dis[i]=map[s][i];//距离为最初值
        
        edg temp;       //<1>这里把每个点与源点s的边都入队
        temp.l=dis[i];
        temp.v=i;
        p.push(temp);
        
        S[i]=0;//最初都不在S集合中
        if(dis[i]==INF)
        pre[i]=-1;
        else
        pre[i]=s;
    }
    S[s]=1;
    dis[s]=0;
    
    for(int j=2;j<=n;j++)//只要遍历n-1次,只有n-1个点
    {
        //找不在S集合中的点与s的最短距离
        /*
        int mindis=INF;
        int m=s;
        for(int i=1;i<=n;i++)
        {
            if(!S[i]&&dis[i]!=INF)//i不在S集合中,dis[i]不为INF
            {
                if(dis[i]<mindis)
                {
                    mindis=dis[i];
                    m=i;
                }
            }
        }
        //mindis,m
        */
        S[m]=1;
        
        edg q=p.top();  //<2>取最短的边
        p.pop();
        int mindis=q.l;
        int m=q.v;
        //更新距离
        for(int i=1;i<=n;i++)
        {
            if(map[m][i]<INF&&!S[i])
            {
                
                if(dis[m]+map[m][i]<dis[i])
                {
                    dis[i]=dis[m]+map[m][i];
                    pre[i]=m;
                    
                    q.v=i,q.l=dis[i];//<3>可多次入队,把每次更新的距离都不入队
                    p.push(q);
                }
            }
        }
    }
    //dis[e],path
}
void Printpath()
{
    stack<int> q;
    q.push(e);
    int u=e;
    while(u!=s)
    {
        q.push(u);
        u=pre[u];
    }
    cout<<s;
    while(!empty())
    {
        cout<<' '<<q.top();
        q.pop();
    }
    cout<<endl;
}
int main()
{
    Dijstra();
    Printpath();
	return 0;
}

【上篇】
【下篇】

抱歉!评论已关闭.