【算法每日一练]-图论(保姆级教程 篇1(模板篇)) #floyed算法 #dijkstra算法 #spfa算法

今天开始讲图论

目录

 图的存储

 算任意两点的最短路径:

     floyed算法:

 算一个点到其他所有点的最短距离

    dijkstra算法:

    spfa算法:


        

      

 图的存储

其实:邻接矩阵和链式向前星都能存边的信息,vector只能存点的信息,再搭配上v[]便可存点的权值,如果是树的话也建议vector)

     
    邻接矩阵:(可存边信息)
    邻接表:vector法(存点信息)(也可以搞一个fa[]存每个点父亲)

    链式向前星(存边信息)
    

下面是链式向前星的模板 

#include <bits/stdc++.h>
using namespace std; 
int tot,n,m;
int head[100];//存放每个点起边的标号
struct edge{
	int to,w,next;//to是边终点,next是下一条边的标号(不用存起点,因为我们是通过起点来找边号的)
}e[100];//存储边,每条边都有唯一下标
void add(int u,int v,int w){
	e[++tot].to=v; //这里我们一般从1开始存边,是因为head里面我们默认0时无边 !!!
	e[tot].w=w;
	e[tot].next=head[u];	head[u]=tot;//后来的边就插在最前面(这里有个细节:因为最开始head内容是0,所以最后一个边的next一定是0)
}
int main(){
	int u,v,w;
	cin>>n>>m; //n个点,m个边
	for(int i=1;i<=m;i++){
		cin>>u>>v>>w;
		add(u,v,w);
	}
	for(int x=1;x<=n;x++){//把每个起点都遍历一遍
		for(int i=head[x];i!=0;i=e[i].next){ //遍历每个点连的边i
			cout<<x<<','<<e[i].to<<'\n';
		}
	}	
}

      

      

算任意两点的最短路径:

     
floyed算法:

O(n^3) 可以处理负权图,不能判断负环图
思想:从第一个点开始,循环n次,依次加入每个点,看看因为这个点的加入,所有点间距离因此而变小就更新


int main(){    //floyed算法
	int n;cin>>n;int w[n+1][n+1];
	memset(w,0x3f,sizeof(w));//若是无向图,对角点初始化为0即可,有联系的点间放权值即可;对角点要初始化
	for(int k=1;k<=n;k++)//依次放入每个点进行中转,这一层是可以单独拿出来的
		for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			if(w[i][j]>w[i][k]+w[k][j])//距离变短就更新
				w[i][j]=w[i][k]+w[k][j];		
		}
}

       

        

 算一个点到其他所有点的最短距离

      
spfa算法

O(nm)=O(KV) 可以处理负权图,判断负环图(负环就是一圈相加起来的权值是个负数)

        
思想:先将起点加入队列,每次从队列中取出一个点,遍历相邻边找到因该点加入而距离变小的点更新,更新成功的点重新入队,重复至队空

     

bellman-ford算法

时间复杂度O(nm)  可以处理负权图,判断负环图

     

dijkstra算法

O(n^2)或O(nlogn)  只能处理非负权图

        
思想:每次贪心地选出一个最小路径的点变成白点(确定点),遍历相邻边找到因该点加入而距离变小的点更新,重复至队空(​​​​​​​白点自动会跳过)

(如果出现负权,这会直接导致选白点的时候就出错了,因此就不能使用该算法)

      

       

题: 

 

                

dijkstra算法:

(原理:贪心思想,确定白点的过程就是贪心,故不能处理负边权) 

             
1. 初始化dis[s]=0,其余点dis为无穷大.
2. 取出队中dis值最小的蓝点cur,变成白点后遍历周围点v,当dis[cur]+w<dis[v],就更新dis[v] (若cur已为白点,就跳过,这点不同于spfa)
3,被更新的点入队,等待重新更新周围点
4,重复操作,直到队空,也就是所有点都变成了白点

      
(注意队列一些点的dis值会越来越多,分两种情况:(对蓝点)取出来的一定是可以变成白点的,不用管; (对白点)dis中值一定比队列中的小,我们跳过即可)

      
我们提供有两种判断办法:
第一种是对出队元素pos的dis和dis[cur]比较,若不相等则说明选出旧白点了,就跳过
第二种方法是对已经成为白点的进行标记,若出队元素早已经是白点了,就跳过
     

        

#include <bits/stdc++.h>                
using namespace std;
typedef pair<int,int> pa;  //pair中first是距离,second是起点到的它点
const int N=1e5+10,M=2e5+10;
int n,m,s,t,tot;
int pre[N];
int head[N],dis[N],vis[N]; //head[i]存放起点i周围的边号,vis标记此点是否为白点(即已确定的点)
struct edge {int to,w,next; } e[M];//如果N,M没有const修饰,这里要报错的
priority_queue<pa,vector<pa>,greater<pa>> Q; //小根堆,按dis升序排列

void add(int u,int v,int w) {e[++tot]=(edge){v,w,head[u]};head[u]=tot;}
void dijkstra(int s) {
	memset(dis,0x3f,sizeof(dis));dis[s]=0;
	Q.push(make_pair(0,s));  //make_pair函数的返回值是一个pair,功能是将两个数据合成一个pair
	while (!Q.empty()) {
		int cur=Q.top().second;Q.pop();//出队就相当于取出最小蓝点
		if (vis[cur]) continue;//跳过旧白点
		vis[cur]=1;
		for (int i=head[cur];i;i=e[i].next) { //i为边号  遍历cur连向周围所有边i的点v
			int v=e[i].to,w=e[i].w; 
			if (dis[cur]+w<dis[v]) dis[v]=dis[cur]+w,Q.push(make_pair(dis[v],v));//更新后就要入队,等待重新更新周围点
			
		}
	}
}
int main() {
	cin>>n>>m>>s;int u,v,w;
	for (int i=1;i<=m;++i) {
		cin>>u>>v>>w;
		add(u,v,w);
	}
	dijkstra(s);
	for (int i=1;i<=n;++i) cout<<dis[i]<<' ';
	return 0;
}
//另一个判断方式+具体路径输出
void print(int u){
	if(u==0)return;
	print(pre[u]);
	cout<<u<<"->";
}
void dijkstra(int s) {
	memset(dis,0x3f,sizeof(dis));dis[s]=0;
	Q.push(make_pair(0,s));  
	while (!Q.empty()) {
		int pos=Q.top().second,dis_=Q.top().first; Q.pop();
		if (dis_!=dis[pos]) continue;//跳过旧白点
		for (int i=head[pos];i;i=e[i].next) { 
			int to=e[i].to,w=e[i].w;   
			if (dis[pos]+w<dis[to]) dis[to]=dis[pos]+w,pre[v]=cur,Q.push(make_pair(dis[to],to));
		}
	}
}
main:
	for (int i=1;i<=n;++i) {
		cout<<dis[i]<<": ";
		print(i);cout<<'\n';
	}

spfa算法步骤:

(原理就是线性dp,由以确定点按拓扑序推下个未确定点,然后未确定点由前面多个以确定点决策,就是按层递推)

     
1. 初始化dis[s]=0,其余dis为无穷大(vis[s]=1)
2,cur出队,遍历周围点v,当dis[cur]+w<dis[v],就更新dis[v](vis[cur]=0)
3,(松弛,入队)被更新的且不在队伍的点入队,等待重新更新周围点(vis[v]=1)(这一步与dijkstra不同,因为已经入过队的可能还会入队,故可处理负边权)
4,重复操作,直到队空
      

不过此题卡spfa,但是因为还是要给出来,因为spfa算法可用地方太多了,比如spfa还可以处理最长路问题

#include <bits/stdc++.h>
using namespace std;  
const int N=1e4, M=1e4;
int head[N],vis[N],dis[N],tot,n,m;//head是表头(head[i]表示i起点的边号),vis表示该点是否已在队列中,为了防止同个点重复入队
struct node{int to,w,next;} e[M];
void add(int u,int v,int w){e[++tot]=(node){v,w,head[u]};head[u]=tot;}
void spfa(int t){
	queue<int> q;
	memset(dis,0x3f,sizeof(dis));
	dis[t]=0;	vis[t]=1; //注意vis等于1表示队列中已经存在此点
	q.push(t);
	while(!q.empty()){
		int cur=q.front();	q.pop();
		vis[cur]=0;//扩展后此点出队
		for(int i=head[cur];i;i=e[i].next){//i是边号  遍历点cur连向的周围边i的点v
			int v=e[i].to,w=e[i].w;
			if(dis[v]>dis[cur]+w){//判断是否需要更新,更新过的且不在队伍的点才入队,方便找更优解
				dis[v]=dis[cur]+w;
				if(!vis[v])q.push(v),vis[v]=1;
			}
		}
	}
}
int main(){
	int n,m,t;
	cin>>n>>m>>t;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
	}
	spfa(t);
	for(int i=1;i<=n;i++){
		cout<<dis[i]<<" ";
	}
	return 0;
}

         

 题目:我们把上百件衣服从商店运回赛场,求最短的从上商店到赛场的路线

       
输入:第一行N(<=100),M(<=10000),N表示有几个路口(1号路口是商场所在地,n号是赛场)M表示有几条路,N=M=0时输入结束,接下来M行每行包括A,B,C表示A,B两口路需要耗时C时间

      
输出:对每组输入,输出一行,表示工作人员从商店到赛场的最短时间

    
样例: 2 1           输出:3
            1 2 3                   2
            3 3
            1 2 5
            2 3 5
            3 1 2
            0 0

#include <bits/stdc++.h>                
using namespace std;
const int N=1e4+10;
const int M=1e4+10;
long long dis[N],u[N],v[N],w[N];//按边初始化无向图
int n,m,cnt;
long long ans;
long long bellman_fold(int s,int t){
	memset(dis,0x3f,sizeof(dis));//初始化无穷大
	dis[s]=0;
	for(int i=1;i<=n-1;i++){//最多松弛n-1次
		int check=0;//是否可以提前结束松弛
		for(int j=1;j<=cnt;j++){//对每条边进行松弛,更新dis
			if(dis[u[j]]+w[j]<dis[v[j]]){
				dis[v[j]]=dis[u[j]]+w[j];
				check=1;
			}
		}
		if(check==0)break;
	}
	return dis[t];
}
int main(){
	while((cin>>n>>m)&&(n+m)){
		 cnt=1;
		for(int i=1;i<=m;i++){//初始化无向图(按边),因为只需要用到每条边,所有初始化只需要按边初始化即可
			int x,y,z;
			cin>>x>>y>>z;
			u[cnt]=x;v[cnt]=y;w[cnt]=z;//w表示每条边的长度,u表示对应边的起点,v表示对边的终点,这样方便对每条边访问
			cnt++;
			u[cnt]=y;v[cnt]=x;w[cnt]=z;
			cnt++;
		}
		ans=bellman_fold(1,n);
		cout<<ans<<endl;
	}
}

不过bellman我不怎么用,只是给出来一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/145935.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023年【汽车驾驶员(中级)】考试题库及汽车驾驶员(中级)模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 汽车驾驶员&#xff08;中级&#xff09;考试题库根据新汽车驾驶员&#xff08;中级&#xff09;考试大纲要求&#xff0c;安全生产模拟考试一点通将汽车驾驶员&#xff08;中级&#xff09;模拟考试试题进行汇编&…

产品运营的场景和运营策略

一、启动屏 1&#xff0e;概念 启动屏&#xff0c;特指 APP 产品启动时即显示的界面&#xff0c;这个界面一般会停留几秒钟时间&#xff0c;在这个时间内 APP 会在后台加载服务框架、启动各种服务 SDK 、获取用户地理位置、判断有无新版本、判断用户账户状态以及其他系统级别的…

QGIS之十九矢量投影

效果 步骤 1、准备数据 2、Qgis矢量投影 Qgis工具箱中搜索“投影” 3、结果

鸿蒙HarmonyOS从零实现类微信app效果第一篇,基础界面搭建

最近鸿蒙HarmonyOS开发相关的消息非常的火&#xff0c;传言华为系手机后续将不再支持原生Android应用&#xff0c;所以对于原Android应用开发对应的Harmony版本也被一系列大厂提上了日程。作为一个名义上的移动端开发工程师&#xff08;(⊙o⊙)…&#xff0c;最近写python多过A…

【计算机网络】VLAN原理和配置

目录 1、VLAN的原理 1.1、什么是VLAN 1.2、为什么要使用VLAN 1.3、VLAN的三种端口类型 1.4、VLAN的划分方法 2、VLAN的配置 1、VLAN的原理 1.1、什么是VLAN VLAN&#xff08;Virtual Local Area Network&#xff09;即虚拟局域网&#xff0c;是将一个物理的LAN在逻辑上…

十年软件测试老程序告诉你性能测试的左移右移到底能干嘛

常规的性能测试一般都是在测试阶段集成测试时候才开始介入&#xff0c;很容易测试时间不够&#xff0c;可不可以借鉴测试左移右移的思路&#xff0c;更早的介入和发现性能风险&#xff0c;然后在测试阶段更专注于分析优化&#xff1f; 借着这个问题&#xff0c;结合自己的实践…

Maven依赖管理项目构建工具的安装与配置

本篇来自尚硅谷的笔记&#xff0c;在线视频观看&#xff1a;Maven依赖管理项目构建工具&#xff0c;更多笔记欢迎访问&#xff1a;小熊学Java 一、Maven简介 1、为什么学习Maven 1.1、Maven是一个依赖管理工具 ①jar 包的规模 随着我们使用越来越多的框架&#xff0c;或者框…

linux DMA设备驱动详解

一&#xff0c;DMA相关定义&#xff08;fpga、wait_queue 、device、interrupt、 dma_request_channel 函数、dma_start_transfer函数、poll、read&#xff0c;platform总线&#xff09; DMA (直接内存读写)是Direct Memory Access的缩写&#xff0c;也就是内存到内存&#xf…

k8s自定义Endpoint实现内部pod访问外部应用

自定义endpoint实现内部pod访问外部应用 endpoint除了可以暴露pod的IP和端口还可以代理到外部的ip和端口 使用场景 公司业务还还没有完成上云&#xff0c; 一部分云原生的&#xff0c;一部分是实体的 业务上云期间逐步实现上云&#xff0c;保证各个模块之间的解耦性 比如使…

使用GPT-4训练数据微调GPT-3.5 RAG管道

原文&#xff1a;使用GPT-4训练数据微调GPT-3.5 RAG管道 - 知乎 OpenAI在2023年8月22日宣布&#xff0c;现在可以对GPT-3.5 Turbo进行微调了。也就是说&#xff0c;我们可以自定义自己的模型了。然后LlamaIndex就发布了0.8.7版本&#xff0c;集成了微调OpenAI gpt-3.5 turbo的…

敏捷开发中如何写好用户故事

写好用户故事是敏捷开发中非常重要的一环&#xff0c;它们是描述用户需求的核心。以下是一些关于如何编写优秀用户故事的建议&#xff1a; 使用标准模板&#xff1a; 一个常用的用户故事模板是“As a [用户角色]&#xff0c;I want [功能]&#xff0c;so that [价值]”。这种模…

《RT-DETR魔术师》专栏介绍 CSDN独家改进创新实战 专栏目录

RT-DETR魔术师专栏介绍&#xff1a; https://blog.csdn.net/m0_63774211/category_12497375.html ✨✨✨魔改创新RT-DETR &#x1f680;&#x1f680;&#x1f680;引入前沿顶会创新&#xff08;CVPR2023&#xff0c;ICCV2023等&#xff09;&#xff0c;助力RT-DETR &#…

【C#学习】常见控件学习

】 如何让Button控件只显示图片 第一步&#xff1a;设置按钮背景图片&#xff0c;并且图片随按钮大小变化 第二步&#xff1a;设置按钮使之只显示图片 button1.FlatStyle FlatStyle.Flat;//stylebutton1.ForeColor Color.Transparent;//前景button1.BackColor Color.Tran…

java项目之共享充电宝管理系统(ssm框架)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的共享充电宝管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 管理员&#xff1a;首页、个…

Linux系统编程——进程的创建

函数名 fork&#xff1a;创建一个子进程 函数原型 pid_t fork(void); 调用该函数时&#xff0c;需包含以下头文件 #include <unistd.h>返回值 fork函数调用成功&#xff0c;返回两次PID &#xff08;1&#xff09;返回值为0&#xff0c;代表当前进程是子进程 &am…

thinkphp 自定义错误页面

在访问无效的UI 这个效果不好&#xff0c;要改成自定义的 <?php namespace app\controller;class ErrorController {public function __call($method,$args){return error request!;} }之后就是提示

深度学习之基于YoloV5钢材表面缺陷检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 深度学习技术在计算机视觉领域的应用为表面缺陷检测系统的发展提供了强大的推动力。本文将介绍基于YoloV5的钢材表面…

UE5、CesiumForUnreal实现加载GeoJson绘制墙体(Wall)功能(StaticMesh方式)

文章目录 1.实现目标2.实现过程2.1 实现原理2.2 具体代码2.3 应用测试2.3.1 流动材质2.3.2 蓝图测试3.参考资料1.实现目标 与上一篇以StaticMesh方式实现面类似,本文通过读取GeoJson数据,在UE中以StaticMeshComponent的形式绘制出墙体数据,并支持Editor和Runtime,在Editor下…

2013年03月14日 Go生态洞察:走向Go 1的道路 ️

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

zabbix的服务器端 server端部署

zabbix的服务器端 server 主机iplocalhost&#xff08;centos 7&#xff09;192.168.10.128 zabbix官网部署教程 但是不全&#xff0c;建议搭配这篇文章一起看 zabbixAgent部署 安装mysql 所有配置信息和Zabbix收集到的数据都被存储在数据库中。 下载对应的yum源 yum ins…