最短路(Dijkstra)算法

一、邻接矩阵,时间复杂度O(n^2) 

//Dijkstra的最短路算法
#include<bits/stdc++.h>
using namespace std;
const int MAX_N=10000;
const int MAX_M=100000;
const int inf=0x3f3f3f3f;
struct edge{
	int v,w,next;
}e[MAX_M];
int p[MAX_N],eid,n;
void mapinit(){
	memset(p,-1,sizeof(p));
	eid=0;
} 
void insert(int u,int v,int w){//插入带权有向边
    e[eid].v=v;
    e[eid].w=w;
    e[eid].next=p[u];
    p[u]=eid++;	 
}
void insert2(int u,int v,int w){//插入带权双向边 
	insert(u,v,w);
	insert(v,u,w);
}
int dist[MAX_N];//存储单源最短路的结果
bool vst[MAX_N];//标记每个顶点是否在集合U中
bool dijkstra(int s){
	memset(vst,0,sizeof(vst));
	memset(dist,0x3f,sizeof(dist));
	dist[s]=0;
	for(int i=0;i<n;++i){
		int v,min_w=inf;//记录dist最小的顶点编号和dist值
		for(int j=0;j<n;++j){
			if(!vst[j]&&dist[j]<minw){
				minw=dist[j];
				v=j;
			}
		} 
		if(min_w==inf){
			return false;//没有可用的点,算法结束,说明有顶点无法从源点到达	 
		}
		vst[v]=true;//将顶点v加入集合U中
		for(int j=p[v];j+1;j=e[j].next){
			//如果和v相邻的顶点x满足dist[v]+w(v,x)<dist[x],则更新dist[x],这一操作被称为松弛操作
			int x=e[j].v;
			if(!vst[x]&&dist[v]+e[j].w<dist[x]){
				dist[x]=dist[v]+e[j].w;
			}
		} 
	}
	return true;//源点可以到达所有的点,算法正常结束 
} 

二 邻接矩阵 时间复杂度O(n^2)

#include <iostream>
#include <string.h>
using namespace std;
const int inf=0x3f3f3f3f;
int G[110][110];
int dist[110];
bool vst[110];
int n,m;
void dijkstra(int s){
    memset(vst,false,sizeof(vst));
    memset(dist,0x3f,sizeof(dist));
    dist[s]=0;
    for(int i=0;i<n;++i){
        int v,min_d=inf;
        for(int j=1;j<=n;j++){
            if(!vst[j]&&dist[j]<min_d){
                min_d=dist[j];
                v=j;
            }
        }
        vst[v]=true;
        for(int j=1;j<=n;++j){
            dist[j]=min(dist[j],dist[v]+G[v][j]);
        }
    }
}
int main() {
    cin>>n>>m;
    memset(G,0x3f,sizeof(G));
    for(int i=0;i<m;++i){
        int u,v,len;
        cin>>u>>v>>len;
        G[u][v]=G[v][u]=len;
    }
    dijkstra(1);
    for(int i=1;i<=n;++i){
        cout<<dist[i]<<" ";
    }
    return 0;
}

三、堆优化的Dijkstra 时间复杂度O((V+E)*lgV)

//小根堆优化的Dijkstra示例代码如下
const int MAX_N=10000;
const int MAX_M=100000;
const int inf=0x3f3f3f3f;
struct edge{
	int v,w,next;
}e[MAX_M];
int p[MAX_N],eid,n;
void mapinit(){
	memset(p,-1,sizeof(p));
	eid=0;
} 
void insert(int u,int v,int w){//插入带权有向边 
	e[eid].v=v;
	e[eid].w=w;
	e[eid].next=p[u];
	p[u]=eid++;
}
void insert2(int u,int v,int w){//插入带权双向边
    insert(u,v,w);
	insert(v,u,w); 
}
typedef pair<int,int>PII;
/*用set伪实现一个小根堆,并具有映射二叉堆的功能
 堆中pair<int,int>的second表示顶点下标,
 first表示该顶点的dist值*/ 
set<PII,less<PII> >min_heap;
int dst[MAX_N];//存储单源最短路的结果
bool vst[MAX_N];//标记每个顶点是否在集合U中
bool dijkstra(int s){
	//初始化dist、小根堆和集合U
	memset(vst,0,sizeof(vst));
	memset(dist,0x3f,sizeof(dist));
	min_heap.insert(make_pair(0,s));
	dist[s]=0;
	for(int i=0;i<n;++i){
		if(min_heap.size()==0){//如果小根堆中没有可用顶点,说明有顶点无法从源点到达,算法结束
		   return false; 
		}
		//获取堆顶元素,并将堆顶元素从堆中删除
		auto iter=min_heap.begin();
		int v=iter->second;
		min_heap.erase(*it);
		vst[v]=true;
		//进行和普通dijkstra算法类似的松弛操作
		for(int j=p[v];j+1;j=e[j].next){
			int x=e[j].v;
			if(!vst[x]&&dist[v]+e[j].w<dist[x]){
				//先将对应的pair从堆中删除,再将更新后的pair插入堆
				min_heap.erase(make_pair(dist[x],x));
				dist[x]=dist[v]+e[j].w;
				min_heap.insert(make_pair(dist[x],x)); 
			}
		} 
	} 
}   return true;//存储单源最短路的结果 

猜你喜欢

转载自blog.csdn.net/amf12345/article/details/89010091