1. 基础
Dijkstra,单源最短路径算法,要求图中无负环。
-
过程:选点(Black),找周围点(Grey),松弛,选点(Black),找周围点(Grey),松弛,……,直到没有点。
-
使用邻接表
map[maxn][maxn]
存储边关系,bool
型数组存储颜色 (比如1=white, 0=black/grey),dist[maxn]
存储源点到各个点的距离。 -
通过判断
dist[i]
是否为INF可以得出该点是grey点还是white点。 -
拓展周围点时的距离关系:
dist[i]=dist[pre]+map[pre][i]
例题1:P1359 租用游艇
裸的dijkstra可以直接过,塔塔露听了都要落泪。甚至代码都没有看的必要。
2. 优化
1)链式前向星
一种存表方式,在代码好写和效率高之间中规中矩。 静态建邻接表,时间效率为O(m),空间效率也为O(m),遍历效率也为O(m)。
2)重载运算符
例如:
struct node { //定义一个结构体node(节点)
int x;
int y;
int len; //node中有3个成员变量x,y,len
inline bool operator <(const node &a)const {
return len<a.len;
}
};
重载<操作符。可以对两个node使用<操作符进行比较;括号中的const表示参数a对象不会被修改,最后的const表明调用函数对象不会被修改。
inline
:只有当函数非常短小的时候它才能得到我们想要的效果,如果内联函数不能增强性能,就避免使用它。
在函数声明或定义中,函数返回类型前加上关键字inline,即可以把函数指定为内联函数。这样可以解决一些频繁调用的函数大量消耗栈空间(栈内存)的问题。关键字inline必须与函数定义放在一起才能使函数成为内联函数,仅仅将inline放在函数声明前面不起任何作用。inline是一种“用于实现”的关键字,而不是一种“用于声明”的关键字。
3)堆优化
- 使用
priority_queue
实现优化。STLyyds
- 参考:Nemlit的题解
- 代码:
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
const int maxn=10005;
const int maxm=500005;
const int INF=0x3f3f3f;
const int outinf=2147483647;
int n,m;
bool s[maxn];
LL dis[maxn];
struct Edge{
int to;
int w;
int next;
};
Edge edge[maxm];
int head[maxn];
int ctr=0;
void add_edge(int u,int v,int w){
ctr++;
edge[ctr].to=v;
edge[ctr].w=w;
edge[ctr].next=head[u];
head[u]=ctr;
}//链式向前星存法
struct node{
int w,now;
inline bool operator < (const node &x) const{
return w>x.w;
}//重载运算符
};
priority_queue<node>q;//也可以使用pair结构
void dijkstra(int v0){
int MIN=INF+1;
dis[v0]=0;//初始化
q.push((node){0,v0});//从v0-v0的长度为0的边入队,满足循环的起始条件
while(!q.empty()){
node x=q.top();//取堆顶边,x是边的编号
q.pop();//出队
int u=x.now;//u是编号为x的边的终点
if(s[u]) continue;//如果该边已涂黑,重来
s[u]=1;//涂黑
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;//编号为i的边,起点为u,终点为v
if(dis[v]>dis[u]+edge[i].w){
dis[v]=dis[u]+edge[i].w;//松弛
q.push((node){dis[v],v});//入队
}
}
}
}
void prepare(){
memset(dis,0x3f,sizeof(dis));
memset(head,-1,sizeof(head));
memset(s,0,sizeof(s));
for(int i=1;i<=m;i++) edge[i].w=INF;
}
int main(){
int v0; prepare();
scanf("%d%d%d",&n,&m,&v0);
for(int i=0;i<m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
}
dijkstra(v0);
for(int i=1;i<=n;i++){
if(dis[i]>=INF) printf("%d ",outinf);//不知道为什么这里写==会卡掉一个解
else printf("%lld ",dis[i]);
}
return 0;
}