特点:是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。

举例说明:

Dijkstra算法-LMLPHP

图例来自《算法导论》

注意:要求图中不存在负权边。

朴素:

void init()
{
	memset(vis,0,sizeof(vis));	memset(d,0,sizeof(d));	memset(p,0,sizeof(p));
	vis[sta]=1;
	for(int i=1;i<=n;++i)		d[i]=a[sta][i];
	for(int i=1;i<=n;++i)		p[i]=sta;
	d[sta]=0;	p[sta]=0;
}
void Dijkstra()
{
	int k;	init();
	for(int i=1;i<=n-2;++i)
	{
		m=max1;
		for(int j=1;j<=n;++j)
		{
			if(d[j]<m && !vis[j])
			{m=d[j];	k=j;}
		}
		if(m==max1)		break;
		vis[k]=1;
		for(int j=1;j<=n;++j)
			if(d[k]+a[k][j]<d[j])
			{
				d[j]=d[k]+a[k][j];
				p[j]=k;
			}
	}
	printf("%d",d[end]);
	return ;
}

堆优化:

#include<bits/stdc++.h>
#define MAXN 100010
#define MAXM 500010
#define INF 0x3f3f3f3f
struct EDGE{int to,dis,next;}	e[MAXM];
struct node
{
    int dis,pos;
    bool operator <( const node &x ) const	{return x.dis < dis;}
    //重定向
};
std::priority_queue< node > q;
int n,m,s;
int adj[MAXN],dis[MAXN],cnt;
bool vis[MAXN];
void addedge(int u,int v,int d)	//链式前向星
{
    ++cnt;
    e[cnt].dis=d;	e[cnt].to=v;
    e[cnt].next=adj[u];
    adj[u]=cnt;
}
void Dijkstra()
{
    dis[s]=0;	q.push(( node ){0,s});	//先将源点入队列
    while(!q.empty())
    {
        node temp=q.top();	q.pop();
        int x=temp.pos;
        	if(vis[x])	continue;		//对未访问节点进行扫描
        vis[x]=1;
        for(int i=adj[x];i;i=e[i].next)
        {
            int y=e[i].to;
            if(dis[y]>dis[x]+e[i].dis)		//三角不等式
            {
                dis[y]=dis[x]+e[i].dis;
                if(!vis[y])
                    q.push( (node){dis[y], y} );	//邻接节点入队列
            }
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=n;++i) dis[i]=INF;		//初始化
    for(int i=0;i<m;++i)
    {
        int u,v,d;	scanf("%d%d%d",&u,&v,&d);
        addedge(u,v,d);
    }
    Dijkstra();
    for(int i=1;i<=n;++i)	printf("%d ",dis[i]);
    return 0;
}

做题感悟:

  • 有的题目是在问题中套着最短路的模型,要分析出题目中所求的“路径”,然后使用Dijkstra算法。
  • 在“三角不等式”的部分注意,有些题目是运用Dijkstra的思想,但最后所求答案的计算公式并是不“三角不等式”。
07-28 09:23