d i j k s t r a dijkstra dijkstra算法简述:
定义 d i s [ i ] dis[i] dis[i]表示节点 i i i到起点的距离
d i s [ i ] dis[i] dis[i]在初始时,除起点外,全部为极大值
每一次寻找 d i s [ i ] m i n dis[i]_{min} dis[i]min,并用其更新与之相连的每个节点。
伪代码:
for(每个顶点)找出dis最小的顶点x(没有访问过);
for(每个与x相连的顶点y)
dis[y]=min(dis[y],dis[x]+x与y相连边的边权)
}
考虑优化寻找 d i s m i n dis_{min} dismin的过程:每次都要 O ( n ) O(n) O(n)比较每个顶点
使用优先队列( p r i o r i t y _ q u e u e priority \_ queue priority_queue): O ( l o g 2 n ) O(log_{2}n) O(log2n)得到 d i s [ i ] dis[i] dis[i]最小值
用 p a i r pair pair存储。first设为 d i s [ i ] dis[i] dis[i], s e c o n d second second设为 i i i(自动按照 f i r s t first first排序)
由于 p r i o r i t y _ q u e u e priority \_ queue priority_queue默认为大根堆(即从大到小排序),可以将 d i s [ i ] dis[i] dis[i]全部置为相反数,就会从小到大排序了。当然,也可以直接更改 p r i o r i t y _ q u e u e priority \_ queue priority_queue本身的定义。
即设为 p r i o r i t y _ q u e u e < p a i r , v e c t o r < p a i r < i n t , i n t > > , g r e a t e r < p a i r < i n t , i n t > > > priority \_ queue
例题:洛谷P4779单元最短路径(标准版)
#include
using namespace std;
int n,m,s;
struct Edge{
int next,w,to;
}e[200007];
int e_cnt,head[100007];
int d[100007],vis[100007];
priority_queue<pair<int,int> > q;
int Read(){
char ch=getchar();
int flag=1,res=0;
while(ch<'0'||ch>'9'){
if(ch=='-')flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
res=res*10+ch-'0';
ch=getchar();
}
return flag*res;
}
void add_edge(int u,int v,int w){
e[++e_cnt].next=head[u];
e[e_cnt].to=v;
e[e_cnt].w=w;
head[u]=e_cnt;
return;
}
int main(){
memset(d,0x3f,sizeof(d));
memset(vis,0,sizeof(vis));
n=Read();m=Read();s=Read();
for(int i=1;i<=m;++i){
int u=Read(),v=Read(),w=Read();
add_edge(u,v,w);
}
d[s]=0;
q.push(make_pair(0,s));
while(!q.empty()){
int x=q.top().second;
q.pop();
if(vis[x])continue;//记得判断
vis[x]=1;
for(int i=head[x];i;i=e[i].next){
int y=e[i].to,z=e[i].w;
if(d[x]+z<d[y]){
d[y]=d[x]+z;
q.push(make_pair(-d[y],y));
}
}
}
for(int i=1;i<=n;++i)
printf("%d ",d[i]);
return 0;
}