最短路 dijkstra , floyd 和spfa算法 模板

最短路算法还有spfa算法,但是对于比赛的一些数据来说,单纯的求最短路还是用D算法更快更稳定,但是对于有负权值的边来说,就必须用到spfa算法了,所以放在下次说。

floyd 5 行算法,求各个点之间的最短路,相当于遍历每个边,做传递,a-c,c-b,那么a就可以通过c到b。时间复杂度O(n^3)

ps:一般就这种用邻接矩阵存好点

模板代码:

void read(){
	memset(g,0x3f,sizeof d);
	scanf("%d%d",&n,&m);
	for(int i=1;i <= n;i++) d[i][i] = 0;
	for(int i = 1;i <= m;i ++){
		int x,y,w;scanf("%d%d%d",&x,&y,&w);
		d[x][y] = d[y][x] = w;
	}	
	//memcpy(dis,g,sizeof g);
}
void floyd(){
	for(int k=1;k<=n;k++)//这里要先枚举k(可以理解为中转点)
	for(int i=1;i<=n;i++){
		if(i==k || d[i][k]==inf) continue; //剪枝
		for(int j=1;j<=n;j++)
		d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
		//松弛操作,即更新每两个点之间的距离
        //松弛操作有三角形的三边关系推出
        //即两边之和大于第三边
	}
}

dijkstra算法:

Dijkstra是基于一种贪心的策略,首先用数组dis记录起点到每个结点的最短路径,再用一个数组保存已经找到最短路径的点

然后,从dis数组选择最小值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点记为已经找到最短路

此时完成一个顶点,再看这个点能否到达其它点(记为v),将dis[v]的值进行更新

不断重复上述动作,将所有的点都更新到最短路径

这种算法实际上是O(n^2)的时间复杂度,但我们发现在dis数组中选择最小值时,我们可以用一些数据结构来进行优化。

其实我们可以用STL里的堆来进行优化,堆相对于线段树以及平衡树有着常数小,码量小等优点,并且堆的一个巧妙的性质就是可以在nlogn的时限内满足堆顶是堆内元素的最大(小)值。

//送一个路径保存

#include
using namespace std;
const int N = 500010;
const int INF = 2147483647;
typedef pair P;
#define MP make_pair
#define F first
#define S second
int n,m,s,cnt;
int ver[N],nex[N],edge[N];
int head[N],vis[N],dis[N];
priority_queue

q; void add(int a,int b,int w){ ver[++cnt] = b; edge[cnt] = w; nex[cnt] = head[a]; head[a] = cnt; } void init(){ scanf("%d %d %d",&n,&m,&s); memset(head,-1,sizeof head); for(int i=1,a,b,w;i<=m;i++){ scanf(" %d %d %d",&a,&b,&w); add(a,b,w); } } int path[N]; void djstl(){ for(int i=0;i<=n;i++) vis[i] = 0,dis[i] = INF; q.push(MP(0,s)),dis[s] = 0; while(q.size()){ int u = q.top().S; q.pop(); /*int u = q.top().S,uw=q.top().F; q.pop(); if(dis[u]!=-uw) continue;*/ if(vis[u]) continue; vis[u] = 1; for(int i=head[u];~i;i = nex[i]){ int v = ver[i],w = edge[i]; if(dis[v] > dis[u] + w){ dis[v] = dis[u] + w; q.push(MP(-dis[v],v)); path[v] = u; } } } } void getpath(int s,int t){ printf("%d-->%d: %d",s,t,s); stack st; while(path[t]){ st.push(t); t = path[t]; } while(st.size()){ printf("->%d",st.top()); st.pop(); } printf("\n"); } int main(){ init(); djstl(); for(int i=1;i<=n;i++) printf("%d ",dis[i]); printf("\n"); for(int i=2;i<=n;i++) getpath(1,i); return 0; }

#include
using namespace std;
const int N = 500010;
const int INF = 2147483647;
typedef pair P;
#define MP make_pair
#define F first
#define S second
int n,m,s,cnt;
int ver[N],nex[N],edge[N];
int head[N],vis[N],dis[N];
priority_queue

q; void add(int a,int b,int w){ ver[++cnt] = b; edge[cnt] = w; nex[cnt] = head[a]; head[a] = cnt; } void init(){ scanf("%d %d %d",&n,&m,&s); memset(head,-1,sizeof head); for(int i=1,a,b,w;i<=m;i++){ scanf(" %d %d %d",&a,&b,&w); add(a,b,w); } } void djstl(){ for(int i=0;i<=n;i++) vis[i] = 0,dis[i] = INF; q.push(MP(0,s)),dis[s] = 0; while(q.size()){ int u = q.top().S; q.pop(); /*int u = q.top().S,uw=q.top().F; q.pop(); if(dis[u]!=-uw) continue;*/ if(vis[u]) continue; vis[u] = 1; for(int i=head[u];~i;i = nex[i]){ int v = ver[i],w = edge[i]; if(dis[v] > dis[u] + w){ dis[v] = dis[u] + w; q.push(MP(-dis[v],v)); } } } } int main(){ init(); djstl(); for(int i=1;i<=n;i++) printf("%d ",dis[i]); return 0; }

SPFA 算法

void spfa(){
	queue q;
	for(int i = 0;i <= n;i++) dis[i] = INF;
	q.push(s),dis[s] = 0,vis[s] = 1;
	while(q.size()){
		int u = q.front(); q.pop();vis[u] = 0;
		for(int i=head[u];i;i = nex[i]){
			int v = ver[i],w=edge[i];
			if(dis[v] > dis[u] + w){
				dis[v] = dis[u] + w;
				if(!vis[v]){
					q.push(v),vis[v] = 1;
				}
			}
		}
		
	}
}

 

你可能感兴趣的:(图论,模板)