Dijkstra(迪杰斯特拉)算法用来解决单源非负权边最短路问题,即给定图G和起点s,通过算法得到s到其他每个点的最短距离。
算法思想是贪心。核心思路是:创建一个集合S(初始为空),每次找到距离点s最近且不在集合S中的点u,将该点加入到S,访问该点的所有出边点v,判断是否可以通过点u为中介点,使点v到s的距离更近,如果可以则优化d[v]。
至于Dijkstra不能求解含负权的图,是因为dijkstra是贪心的,每次都找一个距源点最近的点u(
d
d
dmin),然后将这个距离当作s-u的最近距离去优化u的出边;但如果存在负权边,那就有可能先通过并不是距s最近的点v,假设v-u的路径有有负的,最终s-v-u的距离小于d[u]。按照贪心的思路去优化,用并不是最近小的dis[u],去优化u的出边,这样dijkstra就被囧掉了。
朴素代码:
复杂度
:
O
(
n
2
)
:O(n^2)
:O(n2)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int inf=1e9+20;
int g[maxn][maxn],d[maxn];
bool vis[maxn]={false};
int n,m,st;
void dijkstra(int s){
fill(d,d+maxn,inf);
memset(vis,0,sizeof vis);
d[s]=0;
for(int i=1;i<=n;i++){
int u=-1,MIN=inf;
for(int j=1;j<=n;j++){
if(vis[j]==false&&d[j]<MIN){
u=j;
MIN=d[j];
}
}
if(u==-1) return ;
vis[u]=true;
for(int j=1;j<=n;j++){
if(vis[j]==false&&g[u][j]!=inf&&d[j]>d[u]+g[u][j]){
d[j]=d[u]+g[u][j];
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&st);
int u,v,k;
fill(g[0],g[0]+maxn*maxn,inf);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&k);
g[u][v]=k;
g[v][u]=k;
}
dijkstra(st);
for(int i=1;i<=n;i++)
cout<<d[i]<<" ";
return 0;
}
堆优化:
复杂度:
O
(
(
n
+
m
)
∗
l
o
g
O((n+m)*log
O((n+m)∗logn
2
)
2)
2)
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int maxn=1007;
const int inf=0x3f3f3f3f;
int head[maxn],cnt,vis[maxn],dis[maxn];
struct ac{
int v,c,nex;
}edge[maxn*4];
void addedge(int u,int v,int c){
edge[++cnt]=(ac){v,c,head[u]};
head[u]=cnt;
edge[++cnt]=(ac){u,c,head[v]};
head[v]=cnt;
}
int n,m;
void init(){
cnt=0;
for(int i=1;i<=n;++i){
head[i]=-1;
vis[i]=0;
dis[i]=inf;
}
}
void dijkstra(int st){
priority_queue<pair<int,int> > pq;
pq.push(make_pair(0,st));
memset(dis,0,sizeof dis);
memset(vis,0,sizeof vis);
dis[st]=0;
while(!pq.empty()){
int u=pq.top().second,uc=dis[u];
pq.pop();
if(vis[u]) continue;
vis[u]=true;
for(int i=head[u];i!=-1;i=edge[i].nex){
int v=edge[i].v,vc=edge[i].c;
if(dis[v]>uc+vc&&vis[v]==0){
dis[v]=uc+vc;
pq.push(make_pair(-dis[v],v));
}
}
}
}
int main(){
init();
scanf("%d%d%d", &n, &m, &st);
int u,v,c;
while(m--){
scanf("%d%d%d", &u, &v, &c);
addedge(u,v,c);
}
dijkstra(st);
for(int i=1; i<=n; i++){
cout<<dis[i]<<" ";
}
}
堆优化板子:洛谷4779