迪杰斯特拉算法 Dijkstra 总结

目录

原理概论

故事引入 

邻接矩阵版 O(N^2版代码)

模板 (这个注释最全,小白不要跳过,有助于理解)

例题

优先队列+链式前向星优化版 O(NlogN+NM)

模板

有向图例题

无向图例题


原理概论

边权无负数时,从未访问的所有点中选一个距源点最短的点,用它来更新别的点,循环操作。相当于三角形两边和大于第三边,边长都是正数时,你从别的点绕到这个最短的点肯定比直接到最短的点距离要大,所以我们可以放心地用这个最短的点更新别的点,这是贪心的思想

故事引入 

邻接矩阵版 O(N^2版代码)

模板 (这个注释最全,小白不要跳过,有助于理解)

#include<cstdio>//有向边无负权有环也行时间复杂度N^2 数组从0开始而不是1 
#include<cstring>//原理:边权无负数时,从未访问的所有点中选一个距源点最短的点,用它来更新别的点,循环操作。相当于三角形两边和大于第三边,边长都是正数时 
using namespace std;//你从别的点绕到这个最短的点肯定比直接到最短的点距离要大,所以我们可以放心地用这个最短的点更新别的点,这是贪心的思想
const int MAX=1e4+10,INF=0x3f3f3f3f;
int g[MAX][MAX];//存储图
bool vis[MAX];//表示这个点的最短路是否确定,也就是他是不是在【寻找源点到其他点的最短距离并用它更新其他的点】这个环节中被访问过的点
int n,m,s;
int dis[MAX];//到源点的最短路
void dijkstra(int s) { //迪杰斯特拉算法 源点为s,寻找各点到源点的最短路
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;//源点到源点距离为0
	for(int i=0; i<n; i++) { //寻找源点到其他点的最短距离并用它更新其他的点,共n个点,所以寻找n次,外层循环时间复杂度为n
		int minn=INF,u=-1;//u使dis[u]最小,minn存放该最小的dis[u]
		for(int j=0; j<n; j++) { //找出一个未被访问过的最短路,即dis[]最小 内层循环1时间复杂度n
			if(!vis[j] && minn>dis[j]) {
				minn=dis[j];
				u=j;
			}
		}
		if(u == -1) return;//找不到小于 INF 的 dis[u], 说明剩下的顶点和起点 s 不连通
		vis[u]=true;//u已被访问
		for(int j=0; j<n; j++) { //逐个更新最短路:如果j未访问且u能到达j且以u为中介点可以使dis[j]更优  内层循环2时间复杂度n 共2n^2
			if(!vis[j] && g[u][j]!=INF && dis[j]>dis[u]+g[u][j])
				dis[j]=dis[u]+g[u][j];//s->j的路径 == s->u->j
		}
	}
}
int main() {
	return 0;
}

例题

Login

注意,这题很坑,数组从0开始的,所以你的数组要是从1开始记得+1,AC代码不贴了,模板加个输入就OK

优先队列+链式前向星优化版 O(NlogN+NM)

模板

#include<cstdio>
#include<iostream>//数组从1开始
#include<cstring>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f,N=1e5+10;
struct node {
	int  to,next,w;
	friend bool operator < (const node &f1, const node &f2) {
		return f1.w > f2.w;
	}
} edge[N];
int n,m,cnt,s,t;
int head[N],dis[N];
bool vis[N];
priority_queue<node> Q;
inline void addedge(int from, int to, int w) {
	edge[cnt].to = to;
	edge[cnt].next = head[from];
	edge[cnt].w = w;
	head[from] = cnt++;
}
inline void init() {
	cnt = 0;
	memset(head, -1, sizeof(head));
	memset(edge, 0, sizeof(edge));
	memset(dis, 0x3f, sizeof(dis));
}
void dijkstra(int s,int t) { //s为源点 t为终点 
	node z;
	z.to=s,z.next=0,z.w=0;
	Q.push(z);
	dis[s] = 0;
	while (Q.size()) {
		z = Q.top();
		Q.pop();
		if(vis[z.to])	continue;//无向图的话请注释掉  因为这是为了剪枝,而无向图不能这么剪枝 
	    vis[z.to]=true;//无向图的话请注释掉 
		int start = z.to;
		for (int i = head[start]; ~i; i = edge[i].next) {
			int end = edge[i].to;
			if (dis[end] > dis[start] + edge[i].w) {
				dis[end] = dis[start] + edge[i].w;
				Q.push({edge[i].to,edge[i].next,dis[end]});
			}
		}
	}
	printf("%d\n", dis[t]);
}
int main() {
	while(~scanf(" %d%d%d%d",&n,&m,&s,&t)) {
		init();
		for (int i = 0; i < m; i++) {
			int from, to, w ;
			scanf(" %d%d%d", &from, &to, &w);
			addedge(from, to, w);
			addedge(to, from, w);//无向图的话请加上 
		}
		dijkstra(s,t);
	}
	return 0;
}

有向图例题

Codeup新家

注意一下s+1,改一下输入输出就AC

无向图例题

[USACO09OCT]Heat Wave G - 洛谷

模板为AC代码

2387 -- Til the Cows Come Home

按我说的该注释的注释掉,该加的加,修改一下输入输出就AC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值