优先队列+狄克斯特拉 求单源最短路
先上模板:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAX 100005
#define MAXN ~(1<<31)
#define pb push_back
#define INF 0x3f3f3f3f
priority_queue<pair<int,int> > p;
int color[MAX];
int d[MAX];
int n;
void dijkstra(int t)
{
for(int i=1;i<=n;i++)
{
d[i]=INF;
color[i]=0;
}
d[t]=0;
p.push(make_pair(0,t));
color[t]=1;
while(!p.empty())
{
pair<int,int> f=p.top();p.pop();
int u=f.second;
color[u]=2;
if(d[u]<f.first*(-1)) continue;
for(int j=0;j<s[u].size();j++)
{
int v=s[u][j].first;
if(color[v]==2)continue;
if(d[v]>d[u]+s[u][j].second)
{
d[v]=d[u]+s[u][j].second;
p.push(make_pair(d[v]*(-1),v));
color[v]=1;
}
}
}
for(int i=1;i<=n;i++)
{
cout<<abs(d[i]==INF?MAXN:d[i])<<' ';
}
cout<<endl;
}
int main()
{
ios::sync_with_stdio(false);
int m,s1;
cin>>n>>m>>s1;
while(m--)
{
int u,v,w;
cin>>u>>v>>w;
s[u].push_back(make_pair(v,w));
}
dijkstra(s1);
return 0;
}
垃圾图论,毁我青春! 图论大法好!
在某次比赛后,我发现我图论的知识盲区有点多,所以下定决心,好好学图论!
之后就陷入自闭! 好好学习!自闭!的无限循环,终于在某一天的下午,一觉起来,恍然大悟!哈哈哈哈哈 !
我不会告诉你我还是什么都不懂的
下面进入正题:
在聊 优先队列版的狄克斯特拉求最短路 之前,我们先要聊聊 普通版本的狄克斯特拉 是什么原理。
其实用我的话说就是条条大路通罗马,一路更比一路短。
什么意思呢?举个例子:
有三个点A,B,C。
A --> B 的距离为 2
B --> C 的距离为 3
A --> C 的距离为 6
显而易见 如果直接选择A --> C 直达,那么其距离大于 A --> B --> C 的距离。
所以狄克斯特拉的算法精髓就是找到这么几个中转站,使得两地的距离最短。
而如果要实现这种想法,还要运用贪心。
我们先设立两个集合,第一个集合是原图,第二个集合是已选的点和备选的点,运用贪心 找到备选的点中路最短的那条,再重复上述步骤。
//
图论的东西很难用言语表达出来,以后会考虑录视频聊,现在就当是我和我自己尬聊吧。ggggggg
//
知道普通的狄克斯特拉求单源最短路劲之后,就要考虑加速和处理更大的数的问题了。
这里我们选择的是使用优先队列来配合狄克斯特拉求最短路劲。
下面是我看到的写的比较好的一篇聊优先队列的文展:
优先队列priority_queue
1.1 存图的方式
vector<pair<int,int> > s[MAX];
对于加权图,最原始的方式就是通过二维数组存储点与点之间的联系,但这样的建图会在数据达到1e5的时候爆炸,所以这里就有了一个更好的存图方式。
即利用vector<pair<int,int>>s[100]来建立它们之间的联系。
其结构组成为:
s[u].first 与u链接的点
s[u].second 与u链接的点的权值
则建图的code如下:
while(m--)
{
int u,v,w;
cin>>u>>v>>w;
s[u].push_back(make_pair(v,w));
}
2.1 优先队列存图
priority_queue<pair<int,int> > p;
我们可以将选好的第一个点放入优先队列p,再理由优先队列的性质,可以保证每次取出的top是所有路劲的最小值。
但这里需要注意一点:默认情况下的优先队列是从大到小的,如果要选取最小的数,就要再*-1。
3.1 核心步骤+注释
while(!p.empty())
{
pair<int,int> f=p.top();p.pop();//每次取出的数一定是最短路径的点/其中 first 指向 权值,即路径的长短,second 指向点
int u=f.second;
color[u]=2;//标记该点经过
if(d[u]<f.first*(-1)) continue;//如果在之前找到了比它还小的最短路,就continue
for(int j=0;j<s[u].size();j++)//这一步的目的就是将与u有联系的点压入队列中
{
int v=s[u][j].first;
if(color[v]==2)continue;//如果该点走过就跳过
if(d[v]>d[u]+s[u][j].second)//如果发现有结点联系他们并且可以缩短距离就更行距离
{
d[v]=d[u]+s[u][j].second;
p.push(make_pair(d[v]*(-1),v));//将与u相关的点压入队列中
color[v]=1;
}
}
}