【算法竞赛刷题模板8】基于邻接表或邻接矩阵下的dijkstra算法实现

0.总结

Get to the points firstly, the article comes from LawsonAbs!
  • dijkstra 算法在邻接矩阵中的实现
  • dijkstra 算法在邻接表中的实现

有人可能会问,一个dijkstra算法为啥要搞这么多种实现干嘛?有意思吗? 当然有! 因为针对不同的数据场景,方案就必定不同。

  • 当图的信息可以用邻接矩阵来存储时【比如说顶点数比较小或者图比较稠密时】,dijkstra的算法实现则可以基于邻接矩阵。
  • 当图是稀疏图【比如:顶点数很多,但是边数较少时】,就要用邻接表的这种形式来存储。dijkstra的算法实现则可以基于邻接表。
  • 单说没啥意思,还是结合洛谷的两道题目来讲。

1.dijkstra+邻接矩阵

1.1 题目

P1346 电车

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 题目

P1339 Heat Wave G

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. 相关例题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

说文科技

看书人不妨赏个酒钱?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值