最短路

最短路

多源最短路径

Floyed-Warshall算法

\[弗洛伊德算法,是最简单的多元最短路径算法,可以计算图中任意两点的最短路径。 时间复杂度为 O(N^3) \]

算法描述:

设置\(dis[u][v]\) 表示从\(u\)\(v\)的距离

(1) 初始化

将相连接的点的距离设置为 \(dis[u][v]\)=\(dis[v][u]\)

如果不相连,则\(dis[u][v]=inf\)

(2) 通过中间节点进行拓展

	for(int k=1;k<=n;++k){
		for(int i=1;i<=n;++i){
			for(int j=1;j<=n;++j){
				if(dis[i][j]>dis[i][k]+dis[k][j]&&dis[i][k]!=INF&&dis[k][j]!=INF){
					dis[i][j]=dis[i][k]+dis[k][j];
				}
			}
		}
	}

(3) 最终的出来的 dis[u][v] 则为u到v的最短路径

Floyed 变形

如果图为无边权图,且题求连通性,可以将 dis[u][v]=1,(相连) dis[u][v]=0(不相连)

	for(int k=1;k<=n;++k){
		for(int i=1;i<=n;++i){
			for(int j=1;j<=n;++j){
				dis[i][j]|=(dis[i][k]&&dis[k][j]);
			}
		}
	}

Dijkstra 算法

\[Dijkstra 算法是一种单源最短路径算法,也就是说单次只能计算从一个起点到另外一个起点的最短路,时间复杂度是 O(N^2) ,但是不能处理负边权问题。 \]

算法描述:

设置起点为 s,那么dis[u] 则表示从s到v的最短路径,book[u] 则判断一个点是否被拓展过.(可以通过pre[u]记录前驱节点从而记录路径)

(1)初始化

\[dis[u]=inf \ \ \ u=1,2,3.....n(u\neq s) \\ book[u]=0 \ \ \ u=1,2,3.....n \\ dis[s]=0 \]

(2) 拓展节点

a.从未被访问的节点中找出一个顶点使得 \(dis[u]\) 是最小的

b.将\(u\)标记为确定最短路

c.对于每一个与\(u\)相连接的节点进行拓展更新最短路径

 for(int i=1;i<=n;++i){
        int minx=INF;
        int op=-1;
        for(int j=1;j<=n;++j){
            if(rdis[j]<minx && book[j]!=1){
                minx=rdis[j];
                op=j;
            }
        }
        if(op!=-1){
            book[op]=1;
            for(int j=1;j<=n;++j){
                if(rdis[j]>rdis[op]+dis[op][j]&&!book[j]){
                    rdis[j]=rdis[op]+dis[op][j];
                    fa[j]=op;
                }
            }
        }
    }

(3) 最终求得的 dis[v] 则是s到v的最短路径

Dijkstra 算法优化

我们发现,对于每一次寻找最小值上述过程使用的都是遍历整个数组,但事实上我们可以不用遍历整个数组寻找最小值,对于最小值的寻找我们有着多种方法。

堆优化

我们只需要维护一个小根堆即可求得上述答案

#include<bits/stdc++.h>
using namespace std;
const int size=100010;
int n,m,s;
int head[size],ver[2*size],Next[2*size],edge[2*size],tot;
int dis[size],v[size];
struct node{
	int dis;
	int num;
	bool operator <(const node &x) const{
		return x.dis<dis;
	} 
};
priority_queue<node>q;
void add(int x,int y,int z){
	ver[++tot]=y;edge[tot]=z;Next[tot]=head[x];head[x]=tot;
}
void dija(){
	memset(dis,0x3f,sizeof(dis));
	memset(v,0,sizeof(v));
	dis[s]=0;q.push((node){0,s});
	while(q.size()){
		int x=q.top().num;q.pop();
		if(v[x]) continue;v[x]=1;//只能扩展一次
		for(int i=head[x];i;i=Next[i]){
			int y=ver[i];
			if(dis[y]>dis[x]+edge[i]){
				dis[y]=dis[x]+edge[i];
				if(!v[y]){q.push((node){dis[y],y});}//这里不需要标记
			}
		}
	}
}
int main(){
	scanf("%d %d %d",&n,&m,&s);
	for(int i=1;i<=m;++i){
		int x,y,z;
		scanf("%d %d %d",&x,&y,&z);
		add(x,y,z);
	}
	dija();
	for(int i=1;i<=n;++i){
		printf("%d ",dis[i]);
	}
	return 0;
}
线段树优化
#include<bits/stdc++.h>
using namespace std;
const int size=100010;const int N=100010,M=200010;
inline long long read(){
    long long x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
struct node{
	long long l,r,data,num;
}t[4*N];
int n,m,num,x,y,z,s,tot;
long long k;
const long long inf=1e18;
bool v[N];
int head[N],ver[M],Next[M],poi[N];
long long edge[M],d[N];
void add(int x,int y,int z){
	ver[++tot]=y;edge[tot]=z;Next[tot]=head[x],head[x]=tot;
}
void build(long long p,long long l,long long r){
	t[p].l=l,t[p].r=r;t[p].data=inf;
	if(l==r){t[l].num=p;return;}
	long long mid=(l+r)>>1;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}
void change(long long p,long long v){
	p=t[p].num;t[p].data=v;
	while(p>>=1,p){
		t[p].data=min(t[p*2].data,t[p*2+1].data);
	}
}
long long ask(){
	int p=1;
	while(t[p].l!=t[p].r){
		if(t[p*2].data<t[p*2+1].data) p<<=1;
		else p=p*2+1;
	}
	return t[p].l;
}
int main(){
	n=read();m=read();s=read();
	for(int i=1;i<=m;++i){
		x=read();y=read();z=read();
		add(x,y,z);
	}
	for(int i=1;i<=n;++i){
		d[i]=inf;
	}
	d[s]=0;build(1,1,n);
	change(s,0);	
	for(int i=1;i<=n;++i){
		int x=ask();
		if(d[x]==inf) break;
		for(int j=head[x];j;j=Next[j]){
			int y=ver[j];
			if(d[y]>d[x]+edge[j]){
				d[y]=d[x]+edge[j];
				change(y,d[y]);
			}
		}
		change(x,inf);
	}
	for(int i=1;i<=n;++i){
		if(d[i]!=inf) printf("%lld\n",d[i]);
		else printf("-1\n");
	}
	return 0;
}
posted @ 2022-04-26 23:27  End_donkey  阅读(45)  评论(0编辑  收藏  举报