单源最短路

单源最短路 (但愿嘴短路) 是什么?

讲完了多源最短路 (多余按嘴短路),然后就是单源最短路 (但愿嘴短路)
顾名思义,就是从一个源头出发,到达其他点的最短距离 (希望嘴给短路)(区别于多源最短路 (多余按嘴短路)

算法实现

首先,有请弗洛伊德( F l o y d Floyd Floyd)算法

F l o y d Floyd Floyd

不用我讲了吧,这个算法比较麻烦
不建议使用

然后是贝尔曼-福特( B e l l m a n − F o r d Bellman-Ford BellmanFord)算法

B e l l m a n − F o r d Bellman-Ford BellmanFord

首先看一看

时空复杂度
  1. 时间复杂度
    O ( D o t s ⋅ E d g e ) O(Dots·Edge) O(DotsEdge)
  2. 空间复杂度
    S ( E d g e + D o t s  仅供参考,不一定为真 ) S(Edge+Dots\ \text{仅供参考,不一定为真}) S(Edge+Dots 仅供参考,不一定为真)

看完复杂度,接着再来看看方法
其实,他的本质也是 d p … dp\dots dp
不过,他的想法是松弛(孙悟空:你是怎么练成精的?如来佛祖:放松,别急)

就是先看经过一个点的最短,再看经过两个点的最短, …   … \dots\ \dots  ,最后看经过 n − 1 n-1 n1个点的最短

至于存边 … \dots 那就边集数组

转移方程

B F n ,   E d g e [ i ] . v = m i n { B F n − 1 ,   E d g e [ i ] . v ,   B F n − 1 ,   E d g e [ i ] . u + E d g e [ i ] . w } BF_{n,\ Edge[i].v}=min\{BF_{n-1,\ Edge[i].v}, \ BF_{n-1,\ Edge[i].u}+Edge[i].w\} BFn, Edge[i].v=min{BFn1, Edge[i].v, BFn1, Edge[i].u+Edge[i].w}

降维

S ( E d g e ) S(Edge) S(Edge)是因为边集数组,而 S ( D o t s ) S(Dots) S(Dots)是因为 B F   l i s t BF\ list BF list的存在,那我们就要降维,然后我们便惊喜的发现, n n n是一个没用的东西!我们赶紧删了

代码
未优化
int n,m,dis[N];
struct ed{
	int u,v,wt;
}edge[N];
bool Bellman_ford(int start){
	for(int i=1;i<=n;i++)
	    dis[i]=0x3f3f3f3f3f3f3f3f;
	dis[start]=0;
	for(int i=1;i<=n;i++)
		for(int k=1;k<=ss;k++){
			ed e=edge[k];
			if(dis[e.v]>dis[e.u]+e.wt)
			    dis[e.v]=dis[e.u]+e.wt;
		}
	for(int i=1;i<=ss;i++){
		ed e=edge[i];
		if(dis[e.v]>1e15||dis[e.u]>1e15)
		    continue;
	    if(dis[e.v]>dis[e.u]+e.wt)
	        return true;
	}
	return false;
}
优化
```cpp
int n,m,dis[N];
struct ed{
	int u,v,wt;
}edge[N];
bool Bellman_ford(int start){
	for(int i=1;i<=n;i++)
	    dis[i]=0x3f3f3f3f3f3f3f3f;
	dis[start]=0;
	bool flag;
	for(int i=1;i<=n;i++){
	    flag=true;
		for(int k=1;k<=ss;k++){
			ed e=edge[k];
			if(dis[e.v]>dis[e.u]+e.wt)
			    dis[e.v]=dis[e.u]+e.wt,flag=false;
		}
		if(flag)
		    break;
    }
	for(int i=1;i<=ss;i++){
		ed e=edge[i];
		if(dis[e.v]>1e15||dis[e.u]>1e15)
		    continue;
	    if(dis[e.v]>dis[e.u]+e.wt)
	        return true;
	}
	return false;
}

(均可判负环)

D i j k s t r a Dijkstra Dijkstra

D i j k s t r a Dijkstra Dijkstra算法是解决单源最短路径问题的贪心算法
它先求出长度最短的一条路径,再参照该最短路径求出长度次短的一条路径
直到求出从源点到其他各个顶点的最短路径。
时空复杂度

  1. 时间复杂度
    O ( E d g e 2 + E d g e ⋅ D o t s ) O(Edge^2+Edge·Dots) O(Edge2+EdgeDots)
  2. 空间复杂度
    S ( E d g e + 2 D o t s  仅供参考,不一定为真 ) S(Edge+2Dots\ \text{仅供参考,不一定为真}) S(Edge+2Dots 仅供参考,不一定为真)
上代码
void Dijkstra(int start){
    for(int i=1;i<=n;i++)
        dis[i]=kkk;
	dis[start]=0;
	for(int i=1;i<=m;i++){
		int min_dis=1e15,pos;
		for(int j=1;j<=n;j++)
		    if(vis[j]==false&&dis[j]<min_dis)
		        pos=j,min_dis=dis[j];
		if(min_dis==1e15)
		    return;
		else
		    vis[pos]=true;
		for(int j=1;j<=m;j++){
			ed e=edge[j];
			dis[e.v]=min(dis[e.v],dis[e.u]+e.wt);
		}
	}
}

当然这个还有堆优化,我不会(雾)

好了,现在你学废单源最短路 (但愿嘴短路) 了吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值