C++图网结构算法

目录

一.迪杰斯特拉算法(dijkstra)

1.实现原理:

2.代码实现:

3.例题:

二.spfa算法:

1.实现原理:

2.代码实现:

3.例题:

三.贝尔曼福特(bellman_ford)

1.实现原理:

2.代码实现:

3.例题:

四.弗洛伊德(floyd)

1.实现原理:

2.代码实现:

3.例题:

4.floyd性质探索:

(1).性质一

(2).性质二

(3).性质三

5.floyd传递闭包问题


一.迪杰斯特拉算法(dijkstra)

1.实现原理:

dijkstra算法能实现的原因是它保证了在第一次出队之后,答案一定为最短。也就是出队之后

,一定不会再有更短的路径出队,而dijkstra算法的实现就是基于边权不为负的情况下。

实现步骤:
1.初始化所有点到起点1的距离为正无穷,且dis[1]=0。
2.将起点信息(0,1)入队进行bfs拓展。
3.将起点相连点入队,即(1,2),(2,3)入队。更新点2,3的距离信息。
4.继续拓展节点2,3,将(9,4),(5,4)以及(9,5)入队。此时队首为(5,4),将该节点出队,得到dis[4]=5。
5.继续拓展,直到终点出队...

2.代码实现:

用dis数组记录到每个点的具体距离,每一次循环后,加上相应的边权

priority_queue<node> q;
void dijkstra(int x) {memset(dis,0x3f,sizeof dis);dis[x]=0;q.push({0,x});while(!q.empty()) {node t=q.top();q.pop();int y=t.p;vis[y]=true;for(int i=he[y]; i; i=nxt[i]) {int z=per[i],w=ed[i];if(vis[z]==false && dis[z]>dis[y]+w) {dis[z]=dis[y]+w;q.push({dis[z],z});}}}
}

3.例题:

求单源最短路

给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为正值(边权小于10000)。
请你求出1号点到n号点的最短距离。如果无法从1号点走到n号点,则输出-1。第一行包含整数n和m(n<=1e5,m<=2e5)。
接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。

输出一个整数,表示1号点到n号点的最短距离
如果路径不存在,则输出-1。

用例输入 1 

正确代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,tot,ed[N*2],nxt[N*2],he[N],per[N*2],dis[N*2];
bool vis[N*2];
void add(int x,int y,int z) {//邻接表++tot;per[tot]=y,ed[tot]=z,nxt[tot]=he[x],he[x]=tot;
}
struct node {int d,p;
};
bool operator < (node x,node y) {//重载运算符,明确在优先队列中的排序依据return x.d>y.d;
}
priority_queue<node> q;
void dijkstra(int x) {memset(dis,0x3f,sizeof dis);dis[x]=0;q.push({0,x});while(!q.empty()) {node t=q.top();q.pop();int y=t.p;vis[y]=true;for(int i=he[y]; i; i=nxt[i]) {int z=per[i],w=ed[i];if(vis[z]==false && dis[z]>dis[y]+w) {//比较最小dis[z]=dis[y]+w;q.push({dis[z],z});//入队}}}
}
int main() {cin>>n>>m;for(int i=1; i<=m; i++) {int x,y,z;cin>>x>>y>>z;add(x,y,z);//有向图}dijkstra(1);if(dis[n]==0x3f3f3f3f) cout<<-1;//是否遍历到过,没有就没法从医到这个点else cout<<dis[n];return 0;
}

二.spfa算法:

对于全是正边权的图,我们可以使用dijkstra处理最短路问题。但是如果带有负边边,dijkstra算法无法保证节点出队时一定得到最短路,spfa算法则可以解决这个问题。

1.实现原理:

在求解各点到起点的最小距离dis值时,若某点i产生一个更小的dis[i],那么节点i后续指向的节点都会重新更新,因此我们可以将该点i再次入队,重新更新。

在枚举到3->5的时候由于它小于之前入队的数,所以要进行出对,并进行更新后再次入队。

2.代码实现:

在dijlstra算法的基础上,加入重新出对与再入队的代码

void spfa() {queue<int>q;q.push(1);memset(dis,0x3f,sizeof dis);dis[1]=0;vis[1]=true;while(!q.empty()) {int x=q.front();q.pop();vis[x]=false;//出队之后将原来的标记清除for(int i=he[x]; i; i=nxt[i]) {int y=per[i],w=ed[i];if(dis[x]+w<dis[y]){dis[y]=dis[x]+w;if(vis[y]==false){q.push(y);vis[y]=true;}}}}
}

3.例题:

带负权的最短路计算

给定一个n个点m条边(n<=1e5,m<=2e5)的有向图,图中可能存在重边和自环,边权绝对值小于104。数据保证图中不存在负权回路。

请你求出1号点到n号点的最短距离。如果无法从1号点走到n号点,则输出-1。

第一行包含整数n和m(n<=1e5,m<=2e5)。

接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。

输出一个整数,表示1号点到n号点的最短距离
如果路径不存在,则输出-1。

正确代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,he[N],per[N],nxt[N],tot,dis[N],ed[N];
bool vis[N];
void add(int x,int y,int z) {++tot;per[tot]=y,ed[tot]=z,nxt[tot]=he[x],he[x]=tot;
}
long long read(){int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f;
}
void spfa() {queue<int>q;q.push(1);memset(dis,0x3f,sizeof dis);dis[1]=0;vis[1]=true;while(!q.empty()) {int x=q.front();q.pop();vis[x]=false;for(int i=he[x]; i; i=nxt[i]) {int y=per[i],w=ed[i];if(dis[x]+w<dis[y]){dis[y]=dis[x]+w;if(vis[y]==false){q.push(y);vis[y]=true;}}}}
}
int main() {n=read(),m=read();for(int i=1; i<=m; i++) {int x,y,z;x=read(),y=read(),z=read();add(x,y,z);}spfa();if(dis[n]==0x3f3f3f3f) cout<<-1;else cout<<dis[n];return 0;
}

三.贝尔曼福特(bellman_ford)

上面讲到的两种最短路算法(dijkstra与spfa),他们都是由枚举已知顶点更新未知点。如果我们要在最短路上增加边数限定,即不超过k条边所能构成的最短路,我们就需要将边编号,通过枚举边来实现。

1.实现原理:

枚举边,若左端点值已知,则更新右端点的值。初始化所有点的dis值为正无穷,且dis[1]=0。第1次枚举边:得到dis[2]=1,dis[3]=8第2次枚举边:得到dis[4]=1第3次枚举边:得到dis[5]=2
已知:任意一条路径都是由若干条边组成的链。第一次枚举所有边,可以求出与起点直连的点的最短路。第二次枚举所有边,可以求出不超过2条边所构成的最短路。第k次枚举所有边,可以求出不超过k条边所构成的最短路。

2.代码实现:

使用bellman_ford枚举边,所有用结构体存边并且进行编号。

void bellman_ford(){memset(dis,0x3f,sizeof dis);dis[1]=0;for(int i=0;i<k;i++){memcpy(dis_old,dis,sizeof dis_old);for(int i=1;i<=m;i++) dis[a[i].y]=min(dis[a[i].y],dis_old[a[i].x]+a[i].w);}
}

3.例题:

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。

请你求出从 1 号点到 n 号点的最多经过 k 条边的最短距离,如果无法从 1 号点走到 n 号点,输出 impossible。

第一行包含三个整数 n,m,k。

接下来 m 行,每行包含三个整数 x,y,z,表示存在一条从点 x
到点 y 的有向边,边长为 z。

点的编号为 1∼n。

输出一个整数,表示从 1 号点到 n 号点的最多经过 k 条边的最短距离。

如果不存在满足条件的路径,则输出 impossible。

正确代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
bool vis[N];
vector<int> v[N];
int n,m,k,dis[N],dis_old[N];//用dis_old记录上一个·点,以此来实现标记边
long long read(){int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f;
}
struct node{int x,y,w;
}a[N];
void bellman_ford(){memset(dis,0x3f,sizeof dis);dis[1]=0;for(int i=0;i<k;i++){memcpy(dis_old,dis,sizeof dis_old);for(int i=1;i<=m;i++) dis[a[i].y]=min(dis[a[i].y],dis_old[a[i].x]+a[i].w);}
}
int main() {n=read(),m=read(),k=read();for(int i=1;i<=m;i++) a[i].x=read(),a[i].y=read(),a[i].w=read();bellman_ford();if(dis[n]>0x3f3f3f3f) cout<<"impossible";else cout<<dis[n];return 0;
}

四.弗洛伊德(floyd)

floyd算法专门针对多源最短路问题。floyd可以用一个二维矩阵表示两点之间的最短路径,即我们只需要维护图中最小距离的邻接矩阵。floyd本质上就是通过不断为两点的路径上增加中间点(所以又称为插点法),进而对邻接矩阵进行更新迭代,每加入一个点,矩阵信息就可能变化一次,从而维护该最小距离矩阵。

1.实现原理:

每次枚举是加入一个中间点k,矩阵中有些点对的距离就有可能减小。同时也说明两点的最短路径链上就可能会增加该中间点k。当所有点都作为中间点加入且完成矩阵的更新后,最终矩阵一定存储任意两点之间的距离最小值。

在这幅图中,如果不进行插点,它的初始矩阵是这样的:

1234
100x3f3f3f3f0x3f3f3f3f3
2100x3f3f3f3f8
32503
40x3f3f3f3f0x3f3f3f3f0x3f3f3f3f

0

而在插入1为中间点后,它的矩阵就变成了这样:

1234
100x3f3f3f3f0x3f3f3f3f3
2100x3f3f3f3f4
32503
40x3f3f3f3f0x3f3f3f3f0x3f3f3f3f

0

在插入2为中间点后,它的矩阵又变成这样:

1234
100x3f3f3f3f0x3f3f3f3f3
2100x3f3f3f3f4
32503
40x3f3f3f3f0x3f3f3f3f0x3f3f3f3f

0

最后插入三为中间点后,它的矩阵是这样的:

1234
100x3f3f3f3f0x3f3f3f3f3
2100x3f3f3f3f4
32503
40x3f3f3f3f0x3f3f3f3f0x3f3f3f3f

0

(这只是一个特殊样例,并不是所有可能都只会在插入第一个中间点后才会改变,但经过n-1次插点后路径一定最短)

2.代码实现:

图中存在负边权,且无负权环。n较小,m较大特别稠密,可以使用邻接矩阵存边。最后涉及到多次询问,使用floyd可以维护邻接矩阵,快速求解。

void floyd(){for(int k=1;k<=n;k++){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(k==i||k==j||i==j) continue;//可有可无if(g[i][j]>g[i][k]+g[k][j]) g[i][j]=g[i][k]+g[k][j],pat[i][j]=k;//修改最短路径}}}
}

3.例题:

给定由n个点m条边的构成无向图,边权可能为负,图中可能存在重边,不存自环以及负权环。

现在给定q组询问,请输出每组询问中节点i到j的最短距离及其路径。

第一行 n,m,q,其中n≤500,m≤106,q≤104。
接下来m行表示这两个点之间有边相连,边权绝对值小于10000。
随后q行,代表接下来有q个询问,每个询问由ai​,bi​构成。

一共输出q行,如果两点不存在路径则输出-1,否则每行第一个数字表示两点之间的最短距离,随后输出其路径(如果存在多条最短路径,则输出字典序最小的一个)

正确代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,q,g[505][505],pat[505][505];
long long read() {int x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}return x*f;
}
void floyd(){for(int k=1;k<=n;k++){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(k==i||k==j||i==j) continue;if(g[i][j]>g[i][k]+g[k][j]) g[i][j]=g[i][k]+g[k][j],pat[i][j]=k;}}}
}
void print(int x,int y){if(pat[x][y]==0){cout<<" "<<y;return;}print(x,pat[x][y]),print(pat[x][y],y);
}
int main(){n=read(),m=read(),q=read();memset(g,0x3f,sizeof g);for(int i=1;i<=m;i++){int x,y,w;x=read(),y=read(),w=read();g[x][y]=g[y][x]=min(g[x][y],w);}floyd();for(int i=1;i<=q;i++){int x,y;x=read(),y=read();if(g[x][y]==-1) cout<<-1<<endl;else{cout<<g[x][y]<<" "<<x;print(x,y);cout<<endl;}}return 0;
}

4.floyd性质探索:

(1).性质一

插入中间点的顺序对结果没有影响。

插入一个中间点k后,此时矩阵中任意两点的距离就可能因为该中间点变小,即点k加入了其中两点的路径中。因此,我们只需要保证点1-n都作为中间点插入一次,从而更新矩阵,对插入顺序不作要求。

(2).性质二

floyd算法在第执行k次插点后,最短路径上的边数一定不会超过k+1。

第1次插点后:
两端点由(i->j)直连变成可能加入一个中间点k相连,变成(i->k->j),即最短路径上存在不超过两条边。

第2次插点后:
两端点最短路径有可能还是只有一条边构成(i->j),当然也有可能在第1次插点的基础上增加为两条边构成(i->k->j),此时插点有可能再增加一个点p,变成3条边。即(i->p->k->j) 或 (i->k->p->j)。

第n次插点后:
两端点最短路径上最多由n+2个点构成,即存在不超过n+1条边

(3).性质三

在执行第k次插点操作前,所求任意两端点的最短路径上,一定不包含k以及k后的若干点。

与性质1类似插入某一个点,则说明把该点放到两端点的路径上,从而尝试更新两端点的最小距离。同理,未插入的点是没有更新任意两端点的距离。必不在现有的路径上。

5.floyd传递闭包问题

传递闭包是离散数学中的一个概念,简单来说就是维护关系的传递性。如a<b,b<c则有a<c。
我们以前学习过使用并查集解决部分具有关系传递性的问题。在这里,我们可以通过floyd算法去建立与维护关系矩阵。从而快速判断任意两点是否具备当前关系。可以通过g数组来记录每一个点之间的关系,若g[a][b]=1就代表a>b,若g[a][b]=0,则a<b。如果a、b的关系需要通过k来传递,我们可以通过g[a][b] |= (g[a][k] & g[k][b])来转移他们的关系。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

论文总结:A Survey on Evaluation of Large Language Models-鲁棒性相关内容

A Survey on Evaluation of Large Language Models 只取了鲁棒性相关的内容 LLMs&#xff1a;《A Survey on Evaluation of Large Language Models大型语言模型评估综述》理解智能本质(具备推理能力)、AI评估的重要性(识别当前算法的局限性设 3.2.1 Robustness鲁棒性&#xf…

精通推荐算法12:图神经网络之GCN

1 引言 近年来&#xff0c;图神经网络&#xff08;Graph Neural Networks&#xff0c;GNN&#xff09;在NLP、风控和推荐系统等领域的研究十分火热&#xff0c;其对推荐系统、生物医药、社交网络和知识图谱等非结构化数据有十分优秀的处理能力。基于图神经网络的Embedding表征…

【虚拟化】虚拟化简介 | Hypervisor介绍

目录 一、什么是虚拟化&#xff1f; 二、虚拟化的优点 三、Hypervisor 3.1 Hypervisor概述 3.2 Hypervisor 分类 3.3 Hypervisor 与虚拟机协作技术路线 &#xff08;1&#xff09; 全虚拟化 &#xff08;2&#xff09; 硬件辅助虚拟化 &#xff08;3&#xff09; 半虚…

安装nfs和rpcbind设置linux服务器共享磁盘

1、安装nfs和rpcbind 1.1 检查服务器是否安装nfs和rpcbind&#xff0c;执行下命令&#xff0c;检查服务器是否安装过。 rpm -qa|grep nfs rpm -qa|grep rpcbind 说明服务器以安装了&#xff0c;如果没有就需要自己安装 2、安装nfs和rpcbind 将rpm安装包&#xff1a; libtirpc-…

江科大/江协科技 STM32学习笔记P13

文章目录 TIM定时中断1、TIM简介计数器预分频器自动重装寄存器 2、定时器类型基本定时器主模式触发DAC 通用定时器高级定时器 3、定时器原理定时中断基本结构预分频器时序计数器时序RCC时钟树 TIM定时中断 1、TIM简介 定时器的基准时钟一般都是主频72MHz&#xff0c;如果对72M…

【文心智能体】00后疯感工牌生成器,低代码工作流的简单应用以及图片快速响应解决方案,干活满满,不容错过哦

背景 文心智能体平台&#xff0c;开启新一轮活动&#xff0c;超级创造营持续百日活动。 在AI 浪潮席卷的今天&#xff0c;如雨后春笋般丛生的 AI 应用&#xff0c;昭告着时代风口显然已随之到来。 如何能把握住时代红利&#xff0c;占据风口&#xff0c;甚至打造新风向&#x…

2024护眼大路灯品牌排行前十名新汇总,揭晓年度十大品牌最强王者

护眼大路灯十大品牌哪款最强&#xff1f;在儿童近视问题日渐严峻的今天&#xff0c;选购一款优质的护眼台灯成为了家长们的优先考虑。面对市场上琳琅满目的台灯产品&#xff0c;不少家长在选择时感到无所适从&#xff0c;护眼大路灯十大品牌哪款最强&#xff1f;十大品牌有哪些…

IP 泄露: 原因与避免方法

始终关注您的IP信息&#xff01; 您的IP地址不仅显示您的位置&#xff0c;它包含几乎所有的互联网活动信息&#xff01; 如果出现IP泄漏&#xff0c;几乎所有的信息都会被捕获甚至非法利用&#xff01; 那么&#xff0c;网站究竟如何追踪您的IP地址&#xff1f;您又如何有效…

昇思25天学习打卡营第29天 | 基于MindSpore通过GPT实现情感分类

基于MindSpore框架通过GPT模型实现情感分类展示了从项目设置、数据预处理到模型训练和评估的详细步骤&#xff0c;提供了一个完整的案例来理解如何在自然语言处理任务中实现情感分析。 首先&#xff0c;环境配置是任何机器学习项目的起点。项目通过安装特定版本的MindSpore和相…

【Gin】深度解析:在Gin框架中优化应用程序流程的责任链设计模式(上)

【Gin】深度解析&#xff1a;在Gin框架中优化应用程序流程的责任链设计模式(上) 大家好 我是寸铁&#x1f44a; 【Gin】深度解析&#xff1a;在Gin框架中优化应用程序流程的责任链设计模式(上)✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 本次文章分为上下两部分&#xf…

为什么白酒都用玻璃瓶装?

首先就是因为白酒不能喝太多&#xff0c;人们的酒量有限&#xff0c;可是易拉罐打开就要喝完&#xff0c;并不能再次封上&#xff0c;其次就是易拉罐包装简陋&#xff0c;不符合白酒类的气 质&#xff0c;另外就是因为白酒的酒精含量高&#xff0c;会与易拉罐的铝产生反应&…

看板项目之vue代码分析

目录&#xff1a; Q1、vue项目怎么实现的输入localhost&#xff1a;8080就能自动跳到index页面Q2、组合饼状图如何实现Q3、vue项目如何实现环境的切换Q4、vue怎么实现vue里面去调用js文件里面的函数 Q1、vue项目怎么实现的输入localhost&#xff1a;8080就能自动跳到index页面 …

【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常

问题现象 BeetISQL中间件版本&#xff1a;2.13.8.RELEASE 客户在调用BeetISQL提供的api向yashandb的表中执行batch insert并将返回sequence设置到传入的java bean时&#xff0c;报如下异常&#xff1a; 问题的风险及影响 影响业务流程正常执行&#xff0c;无法获得batch ins…

华为网络模拟器eNSP安装部署教程

eNSP是图形化网络仿真平台&#xff0c;该平台通过对真实网络设备的仿真模拟&#xff0c;帮助广大ICT从业者和客户快速熟悉华为数通系列产品&#xff0c;了解并掌握相关产品的操作和配置、提升对企业ICT网络的规划、建设、运维能力&#xff0c;从而帮助企业构建更高效&#xff0…

js引入和使用

ESMAScript标准 语句基础标准 DOM 针对HTML标签&#xff0c;CSS样式的语言部分 Document Object Model BOM 针对浏览器所使用的开发部分 Browser Object Model js引入 script只能写在head或者body中&#xff09;&#xff0c;如果写在html后这种写法本来就是错误的&am…

LeetCode 637, 67, 399

文章目录 637. 二叉树的层平均值题目链接标签思路代码 67. 二进制求和题目链接标签思路代码 399. 除法求值题目链接标签思路导入value 属性find() 方法union() 方法query() 方法 代码 637. 二叉树的层平均值 题目链接 637. 二叉树的层平均值 标签 树 深度优先搜索 广度优先…

GESP CCF 图形化编程四级认证真题 2024年6月

一、单选题&#xff08;共 10 题&#xff0c;每题 2 分&#xff0c;共 30 分&#xff09; 题号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 答案 C B C D C D A B D C C D A A B 1、小…

乌班图下的vscode粘贴代码后一直在输入CTRLV命令

最近在VMware中使用vscode开发c程序中&#xff0c;拷贝一段代码后&#xff0c;代码界面一直输入CTRLV命令&#xff0c;导致乌班图桌面死掉&#xff0c;无法操作、 解决方法&#xff1a; 1、强制重启。长按电源按钮强制关机&#xff0c;然后再次开机。 2、使用命令行界面。同时…

Excel模拟计算演示-以矩阵乘计算密度为例

Excel模拟计算演示-以矩阵乘计算密度为例 1.参考链接2.CUDA_Occupancy_Calculator截图3.矩阵乘计算密度模拟计算的操作步骤及效果 安装好CUDA之后,/usr/local/cuda-12.1/tools/CUDA_Occupancy_Calculator.xls里会看到"TABLE(,B17)"这样的表达式,原来是模拟计算的结果…

深入理解 Java 虚拟机第三版(周志明)

这次社招选的这本作为 JVM 资料查阅&#xff0c;记录一些重点 1. 虚拟机历史 Sun Classic VM &#xff1a;已退休 HotSpot VM&#xff1a;主流虚拟机&#xff0c;热点代码探测技术 Mobile / Embedded VM &#xff1a;移动端、嵌入式使用的虚拟机 2.2 运行时数据区域 程序计…