第12周学习总结

本文介绍了图论中的三种经典算法:Dijkstra算法用于解决单源最短路径问题,不适用于负权边;Floyd算法可解决多源最短路径,但时间复杂度较高;SPFA算法则能处理负权边。通过实例和代码解释,阐述了每个算法的基本思想和应用场景,并提供了相关在线编程题目的链接以加深理解。
摘要由CSDN通过智能技术生成

本周学习了最小生成树和最短路、贪心,并做了一些最短路的题目。虽然本次题目不多,但我还是没有能够全部A掉,只是A了一小部分。

Dijkstra算法(解决单源最短路径)

它所处理的图不能有负权。基本思路:对得到邻接矩阵,也就是不同位置的关系表示图,通过dijkstra我们能求出1到其他的点的最短路径,通过数组dis[ ]来记下初始化状态下1到其他点的距离,先从权值最小的点开始,搜索他周围能到达的所有的点的路径,将1经过这个点到达他们的总路径相加,与dis[ ]数组中的相对于的点进行比较,如果距离小与dis[]数组中的距离,就更新dis中的距离,在这个离1最近的点找完后,我们再去找下一个离源点近的点,再遍历它周围的所有点,每次找到的离源点最近的点后,都要去标记它已经被使用过了,下次遍历的寻找的时候就不能再 用它了,这样反复。

例题:https://www.luogu.com.cn/problem/P1339

题意:有一个n个点m条边的无向图,求出从s到t的最短路长度。

dijkstra算法,一个最短路径的模板题,对于像我这样的小白去理解算法的实现有很大的帮助。

#include<bits/stdc++.h>
using namespace std;
int arr[3000][3000];//建立一个储存点对应关系的数组 
int vis[3000];//建立一个记录是否走过的数组 
int dis[3000];//建立一个记录最小值的数组 
int main()
{
	memset(arr,60,sizeof(arr));
	memset(vis,0,sizeof(vis));
	memset(dis,60,sizeof(dis));
	int n,m,s,t;
	cin>>n>>m>>s>>t;
	int u,v,w;
	for(int a=0;a<m;a++)
	{
		cin>>u>>v>>w;
		arr[u][v]=w;
		arr[v][u]=w;
	}
	dis[s]=0;//将开始点的距离设为0; 
	for(int a=0;a<n;a++)
	{
		int min=0;
		for(int b=1;b<=n;b++) 
        if(dis[min]>dis[b]&&vis[b]==0) 
          min=b;
		vis[min]=1;//将用过的点标记
		//比较这个点到其他点是否可以更新距离 
	for(int b=1;b<=n;b++)
        if(dis[min]+arr[min][b]<dis[b]) 
        dis[b]=dis[min]+arr[min][b];
	}
	//打印开始点到结束点的距离 
	cout<<dis[t];
}

Spfa算法(解决负权边)

如果一个邻接矩阵中存在负权环,bellman也是可以计算的,先假设它是正权环,进行循环n-1次,循环的n-1次就是正权环有n个顶点的话就最多有n-1条边,这个算法就是来枚举每条边的数据,它的操作会根据所输入的边的次序来进行,每次按所输入边的顺序全部遍历一遍,然后将符合条件的进行操作,知道达到要求的效果,但如果遇到负权环的话,进行了n-1次操作后,再次对这个图进行Ford算法的操作时,发现还可以操作的。所以可以在结尾判断一下,如果可以继续操作的话,那就说它是没有最短路径的。

Floyd算法(解决多源最短路径)

基本思路:如果要求两个点之间的最短距离,不一定是两个点之间的直达距离,有可能是经过转点后的距离,例如从A->B的距离为10,而从A->C的距离为5,从C->B的距离为4,如果走A->C->B的距离的话,那么就更短,如果确定这条路径是最短距离,那么也同样可以确定,A->C的最短路径为5,B->C的最短路径为4,也就是说,如果确定了一条多转站的路径为最短路径后,它所经过的点都为从一点到沿途点的最短路径。

例题:https://www.luogu.com.cn/problem/P2888

题意:想找一条路径从Ai到Bi,使路径上最高的栏的高度最小。

FLOYD算法,枚举每个点,算出总和,同时找距离和最小的一个点记录下标。

#include<bits/stdc++.h>
using namespace std;
int n,m,t,dis[1000][1000],a,b,c,x,y;
int main(){
	cin>>n>>m>>t;
	memset(dis,0x7f,sizeof(dis));	
	for(int i=1;i<=m;i++){
		cin>>a>>b>>c;
		dis[a][b]=c;
	}
	for(int k=1;k<=n;k++){	
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				int s=max(dis[i][k],dis[k][j]);
				if(s!=0x7f7f7f7f&&s<dis[i][j]){	 
					dis[i][j]=s;
				}
			}
		}
	}
	for(int i=1;i<=t;i++){
		cin>>x>>y;
		if(dis[x][y]==0x7f7f7f7f){
			cout<<-1<<endl;
			continue;
		}
		cout<<dis[x][y]<<endl;
	}
	return 0;
}

总结:在这些题目中大部分都是用dijkstra和floyd算法解决的。Dijkstra算法解决单源最短路径,不能解决负权边;Floyd算法解决多源最短路径,时间复杂度高;Spfa算法可以解决负权边。虽然说大部分都是模板题,但是也有很多找不到头绪理解不透题意的题目,看起题目来很懵。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值