题目
题解
链式前向星(存边结构):与链表的结构和查找遍历方式相同,唯一的不同点就是插入的位置。链式前向星每次将新的元素插入链表头。为每一个节点建立一个链表,存入此节点的所有出边。
Dijkstra算法:这个算法要求所有边的权重都为非负值。定义d[i]为从起点到第i个节点的最短路径长度。
算法流程:假设起点为s。1.令d[s]=0 ,其它d[i]为无穷大 2.从没有被标记的节点中找出d[x]最小的节点x,然后标记x 3.枚举x的所有出边x->y(边权为w) ,若d[y]>d[x]+w,则用d[x]+w更新d[y] 4.重复2、3,直到所有节点都被标记。
算法原理:基于贪心思想。每次找到的d[x]最小的节点,不可能再被较大的d[y]更新,所以d[x]必然是s~x的最短路径。
算法优化:动态维护d[x]最小值,减少查找的时间。利用STL 优先队列(大根堆),用STL pair存d[x]和x,将d[x]转成-d[x]存入,把大根堆转化成小根堆。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x7fffffff;
const int maxn=1e5+5;
const int maxm=2e5+5;
int n,m,s,c;
bool v[maxn]; //v[]表示是否标记
int head[maxn],d[maxn]; //head[x]表示节点x的链表头
struct edge{int to,nxt,w;}e[maxm];
inline void add(int from,int to,int w) //加边
{
e[++c].to=to; e[c].w=w; e[c].nxt=head[from]; head[from]=c;
}
priority_queue<pair<int,int> > q;
inline void dijkstra()
{
for(int i=1;i<=n;i++) d[i]=inf;
memset(v,0,sizeof(v)); //初始化
d[s]=0; q.push(make_pair(0,s));
while(q.size())
{
int x=q.top().second; q.pop();
if(v[x]) continue; v[x]=1;
for(int i=head[x];i;i=e[i].nxt) //遍历x的所有出边
{
int y=e[i].to;
if(d[y]>d[x]+e[i].w)
{
d[y]=d[x]+e[i].w;
q.push(make_pair(-d[y],y));
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
int x,y,z; scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
dijkstra();
for(int i=1;i<=n;i++) printf("%d ",d[i]);
return 0;
}