0.总结
Get to the points firstly, the article comes from LawsonAbs!
dijkstra
算法在邻接矩阵中的实现dijkstra
算法在邻接表中的实现
有人可能会问,一个dijkstra算法为啥要搞这么多种实现干嘛?有意思吗? 当然有! 因为针对不同的数据场景,方案就必定不同。
- 当图的信息可以用邻接矩阵来存储时【比如说顶点数比较小或者图比较稠密时】,dijkstra的算法实现则可以基于邻接矩阵。
- 当图是稀疏图【比如:顶点数很多,但是边数较少时】,就要用邻接表的这种形式来存储。dijkstra的算法实现则可以基于邻接表。
- 单说没啥意思,还是结合洛谷的两道题目来讲。
1.dijkstra
+邻接矩阵
1.1 题目
1.2 题意
- 需要抽象题目,结合所学知识,就知道这是一道图论的题,具体说就是
dijkstra
算法的题。
1.3 代码
#include<iostream>
using namespace std;
const int maxN = 105;
const int INF = 0x3f3f3f3f;
int gra[maxN][maxN];//图的信息
int dis[maxN],vis[maxN];
int n;
void dijkstra(){
for(int j = 1;j<=n;j++){
//step1.找出最小的边
int tV,tM = INF;
for(int i = 1;i<=n;i++){
if(!vis[i] && dis[i]<tM){//更新最小边的信息
tM = dis[i];
tV = i;
}
}
vis[tV] = 1;//已经访问过了
//更新其它点的距离值
for(int i = 1;i<=n;i++){
if(!vis[i] && dis[i]>dis[tV]+gra[tV][i]){
dis[i] = dis[tV]+gra[tV][i];
}
}
}
}
int main(){
int a,b;
cin >> n>> a>> b;
int num,ver;
fill(gra[0],gra[0]+maxN*maxN,INF);//图的初始化
fill(dis,dis+maxN,INF);//距离的初始化
fill(vis,vis+maxN,0);
for(int i = 1;i<=n;i++){
cin >> num;
for(int j = 0;j<num;j++){
cin >> ver;
if(j==0)
gra[i][ver] = 0;//不用花费
else
gra[i][ver] = 1;//花费1
}
}
dis[a] = 0;
dijkstra();
if(dis[b]==INF)
cout <<"-1\n";
else
cout << dis[b]<<"\n";
}
1.4 测试用例
3 2 1
2 2 3
2 3 1
2 1 2
3 2 1
2 2 3
1 3
1 2
2.dijkstra
+邻接表
2.1 题目
2.2 题意
- 这题比较直接,就是求单源最短路径,但是因为顶点数较大,所以不适合用邻接矩阵存储,最优的选择就是邻接表。
2.3 关键点
- 使用邻接表存储图
- 优先队列中存储的是Node型节点,其中包括的元素是(id,dis)。即dis[id]=dis。因为要自动排序,所以这里使用优先队列,并在其中定义了排序规则。
- 如果想让数据走得更快些,还可以定义一个已访问的节点数cnt,当cnt==n时,直接跳出while循环。
- 同时需要注意,结构体的重载
<
运算符时,是d1.len< this->len
,而不是this->len<d1.len
,切记,切记!
2.4 代码
#include<iostream>
#include<queue>
const int maxN = 2505;
const int maxM = 6205;
const int INF = 0x3f3f3f3f;
using namespace std;
//图的链式存储时,其边的定义
typedef struct{
int next,to,wei;
}Edge;
//用于放入队列中的节点
typedef struct Dis{
int id,len;//源点到id的距离len
//按照len从大到小排序
bool operator<(const Dis &d1) const{
return d1.len < this->len;
}
}Dis;
Edge edge[maxM];
int head[maxN];//顶点的第一条边
int d[maxN],vis[maxN];//求出源点到各个点的最短路径
//放进队列的
priority_queue<Dis> pq;
int num=0;//边数
void add(int u,int v,int w){
edge[num].next = head[u];
edge[num].to = v;
edge[num].wei = w;
head[u] = num;
num++;
}
//求出最短路径
void dijkstra(int s){
Dis tD;//temp Dis
while(!pq.empty()){//队列非空时,队首就是距离最近的元素
tD = pq.top();
pq.pop();
int curId = tD.id;//当前这个点的编号
if(d[curId]!=tD.len)//说明更短的已经出队过了
continue;
vis[curId] = 1; //防止重复访问
for(int j = head[curId]; j!=-1;j=edge[j].next){//更新curID 到其它点的距离
int eTo = edge[j].to;//当前边的指向
int curWei = edge[j].wei;//当前边的权重
if(!vis[eTo] && d[eTo] > d[curId] + curWei){
d[eTo] = d[curId] + curWei;
pq.push( (Dis){eTo,d[eTo]} );//将当前这个顶点入队
}
}
}
}
int main(){
int n,m,s,t;
int u,v,w;
cin >> n >> m >> s >> t;
fill(head,head+n+1,-1);//初始化为-1
fill(vis,vis+n+1,0);//初始化均为访问
for(int i = 0;i<m;i++){
cin >>u >> v >> w;
add(u,v,w);
add(v,u,w);
}
pq.push((Dis){s,0}) ;//加入队列
fill(d,d+maxN,INF);
d[s] = 0;
dijkstra(s);
cout << d[t] <<"\n";
}
3. 相关例题
- 洛谷 P4779 单源最短路径