Dijkstra 算法是单源最短路径算法,即计算起点只有一个的情况到其他所有点的最短路径,其无法处理存在负边权的情况
Dijkstra算法:
- 定义一个数组dis用来记录这个点到起点的最短距离
- 从已知的起点开始,每次寻找下一个中转点并判断距离是否是当前最短,标记当前走过的点,直到遍历所有的点
我写了三个版本的代码
先看第一个吧
// Dijkstra算法
int n,m;
int dis[1010]; // 记录起点到各个点的最短距离
int vis[1010]; // 标记该点是否走过
int G[1010][1010]; // 存储两个点之间边的权值
void Dijkstra()
{
for(int i=1;i<n;i++){
int minn = 0x3f3f3f3f; // 初始化最短距离为最大
int x;
for(int j=1;j<=n;j++){
if(vis[j] == 0 && dis[j] < minn){
minn = dis[j];
x = j;
}
}
vis[x] = 1;
for(int j=1;j<=n;j++){
if(G[x][j] < 0x3f3f3f3f){
if(dis[j] > dis[x] + G[x][j]){
dis[j] = dis[x] + G[x][j];
// 更新最短距离
}
}
}
}
for(int i=1;i<=n;i++) cout << dis[i] << endl;
}
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++){ // 预处理距离
for(int j=1;j<=n;j++){
if(i == j) G[i][j] = 0;
else G[i][j] = 0x3f3f3f3f;
}
}
int u,v,w;
for(int i=1;i<=m;i++){
cin >> u >> v >> w;
G[u][v] = w;
G[v][u] = w;
}
for(int i=1;i<=n;i++) dis[i] = G[1][i];
// 初始把每个能关联的点之间的距离给dis数组,认为这就是最短距离
memset(vis,0,sizeof vis);
vis[1] = 1; // 起点已经访问过
Dijkstra();
return 0;
}
下面我加了优先队列优化,可以避免每次都要寻找最短距离
优先队列+邻接表
// Dijkstra算法 优先队列 + 邻接表
struct node
{
int pot; // 点
int val; // 权值
node(int a,int b){
pot = a;
val = b;
}
bool operator < (const node &a) const{ // 重载运算符 <
if(val == a.val) return pot < a.pot; // 按照点从大到小
else return val > a.val; // 按照权值从小到大
}
};
vector<node> G[10010];
int n,m;
int dis[10010];
priority_queue<node> q;
void Dijkstra()
{
while(!q.empty()){
node x = q.top(); // 取队首元素 权值最小的
q.pop();
for(int i=0;i<G[x.pot].size();i++){
// 循环队首顶点连接的其他所有点
node y = G[x.pot][i];
if(dis[y.pot] > dis[x.pot] + y.val){
dis[y.pot] = dis[x.pot] + y.val;
// 更新最短距离
q.push(node (y.pot,dis[y.pot]));
// 把当前选定的点和其距离加入优先队列
}
}
}
}
int main(){
cin >> n >> m;
while(m--){
int u,v,w;
cin >> u >> v >> w;
G[u].push_back(node(v,w)); // 记录从点u到v的距离
G[v].push_back(node(u,w));
}
memset(dis,0x3f3f3f3f,sizeof dis);
dis[1] = 0;
q.push(node(1,dis[1]));
Dijkstra();
for(int i=1;i<=n;i++){
cout << dis[i] << endl;
}
return 0;
}
优先队列+链式前向星
int n,m,cnt;
int head[maxn];
int dis[maxn];
int vis[maxn];
struct node
{
int s,w;
bool operator < (const node &u) const{
return w > u.w; // 按权值从小到大排序
}
};
struct Edge
{
int to;
int next;
int val;
}E[maxn];
void add(int u,int v,int w)
{
++cnt;
E[cnt].next = head[u];
head[u] = cnt;
E[cnt].to = v;
E[cnt].val = w;
}
void Dijkstra(int s)
{
memset(dis,0x3f3f3f3f,sizeof dis);
memset(vis,0,sizeof vis);
priority_queue<node> q;
dis[s] = 0;
q.push(node{s,0});
while(!q.empty()){
node temp = q.top(); q.pop();
if(vis[temp.s]) continue;
vis[temp.s] = 1;
for(int i=head[temp.s];i!=-1;i=E[i].next){
if(dis[E[i].to] > dis[temp.s] + E[i].val){
dis[E[i].to] = dis[temp.s] + E[i].val;
q.push(node{E[i].to,dis[E[i].to]});
}
}
}
}
int main(){
int s;
cin >> n >> m;
memset(head,-1,sizeof head);
while(m--){
int u,v,w;
cin >> u >> v >> w;
add(u,v,w);
add(v,u,w);
}
Dijkstra(1);
for(int i=1;i<=n;i++){
cout << dis[i] << endl;
}
return 0;
}