洛谷 P4779 --【模板】单源最短路径(标准版) 题解 By Kimi_Kai

一、题意

首先呢,阐述一下,这是一道最短路模板题,其实看题也看得出来… …,所以呢,我们先得搞清楚什么是最短路

这道题呢,我们用的是dijkstra(俗称低级科斯拉)
如有未搞懂dijkstra的童鞋,可以先看看这片题解

dijkstra详解

既然是用dijkstra,那就得先想到堆优化(上面链接中也说了)。但是呢,最短路径这类问题,堆优化可以用一个优先队列来代替,即priority_queue (头文件要用 #include )

给出这道题几个重点部分:

一、重载

重载(即 friend bool operator)可将一个符号改成自己需要的作用,但只适用于一定范围中,如在结构体中的重载,就只能在使用到结构体的时候用,且没有原来的作用。而在其他部分还是原来的作用

struct node //结构体名称
{
	int a,b; //两个比较变量
	friend bool operator < (const node &x,const node &y) //定义
	{
		return x.a>y.a; //重载
	}
}; //注意,这里要在优先队列中用到,所以不需要有数组
二、添边

最短路径属于图论,而图论不可缺失的就是添边,这时,我们需要用到添边函数addedge了

int to[maxn],val[maxn],head[maxn],ne[maxn],cnt; //to代表从该点到哪个点,val代表边权,ne代表点在数组里的编号,head代表上一个点在数组里的编号,cnt代表现在运行到第几条边了
void edge(int u,int v,int w)//
{
	to[++cnt]=v; //添边
	val[cnt]=w; //存边权
	ne[cnt]=head[u]; //存点编号
	head[u]=cnt; //下一个	
}
三、松弛

松弛是用每一个还没查询过的点,去看能不能更新最短路,且每个点只能松弛一次

void dijkstra(s) //命名
{
    for (int i=1;i<=n;i++)
	{
		dis[i]=0x7f7f7f7f; //因为是最短路,所以先赋无穷大
	}
	dis[s]=0; //到自己的距离为0
	q.push((node){0,s}); //先将自己入队列,这里用结构体打包了到哪个点以及最短路的值
	while(q.size()!=0) //进行操作
	{
		int x=q.top().b; //拿b队列对顶
		q.pop(); //出队
		if(flag[x]==1) continue; //若查询过,则不继续松弛
		flag[x]=1; //标记一下
		for(int i=head[x]; i; i=ne[i]) //开始从当前不为无穷大且没查询过的点中的最短路径点开始松弛
		{
			if(dis[to[i]]>dis[x]+val[i]) //松弛的精华
			{
				dis[to[i]]=dis[x]+val[i]; //如果有更优解,则替换成更优解
				q.push((node){dis[to[i]],to[i]}); //将最短路入队
			}
		}
	}
}

最后给出完整代码

#include
using namespace std;
struct node
{
	int a,b;
	friend bool operator < (const node &x,const node &y)
	{
		return x.a>y.a;
	}
};
priority_queue<node> q;
int head[500005],to[500005],val[500005],ne[500005],cnt;
int n,m,s;
long long dis[100005];
bool flag[100005];
void edge(int u,int v,int w)
{
	to[++cnt]=v;
	val[cnt]=w;
	ne[cnt]=head[u];
	head[u]=cnt;
}
void dijkstra(int s)
{
    for (int i=1;i<=n;i++)
	{
		dis[i]=0x7f7f7f7f;
	}
	dis[s]=0; 
	q.push((node){0,s}); 
	while(q.size()!=0)
	{
		int x=q.top().b;
		q.pop();
		if(flag[x]==1) continue;
		flag[x]=1;
		for(int i=head[x]; i; i=ne[i])
		{
			if(dis[to[i]]>dis[x]+val[i])
			{
				dis[to[i]]=dis[x]+val[i];
				q.push((node){dis[to[i]],to[i]});
			}
		}
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		edge(u,v,w); 
	}
	dijkstra(s);
	for(int i=1;i<=n;i++)
		printf("%ld ",dis[i]); 
	return 0;
}

别走,还有彩蛋!!!

大家可以去看看洛谷的P3371,只需要改一点点就能过哦!

你可能感兴趣的:(洛谷c++题解)