2.13学习总结

1.出差(Bleeman—ford)(spfa)
(dijkstra)
2.最小生成树(prim)(Kruskal)

最短路问题:

出差https://www.luogu.com.cn/problem/P8802

题目描述

AA 国有 �N 个城市,编号为 1…�1…N 小明是编号为 11 的城市中一家公司的员工,今天突然接到了上级通知需要去编号为 �N 的城市出差。

由于疫情原因,很多直达的交通方式暂时关闭,小明无法乘坐飞机直接从城市 11 到达城市 �N,需要通过其他城市进行陆路交通中转。小明通过交通信息网,查询到了 �M 条城市之间仍然还开通的路线信息以及每一条路线需要花费的时间。

同样由于疫情原因,小明到达一个城市后需要隔离观察一段时间才能离开该城市前往其他城市。通过网络,小明也查询到了各个城市的隔离信息。(由于小明之前在城市 11,因此可以直接离开城市 11,不需要隔离)

由于上级要求,小明希望能够尽快赶到城市 NN, 因此他求助于你,希望你能帮他规划一条路线,能够在最短时间内到达城市 �N 。

输入格式

第 11 行:两个正整数 �,�N,M 表示 A 国的城市数量, �M 表示末关闭的路线数量。

第 22 行: �N 个正整数,第 �i 个整数 ��Ci​ 表示到达编号为 ii 的城市后需要隔离的时间。

第 3…�+23…M+2 行: 每行 33 个正整数, �,�,�u,v,c, 表示有一条城市 �u 到城市 �v 的双向路线仍然开通着,通过该路线的时间为 �c。

输出格式

第 11 行:11 个正整数,表示小明从城市 11 出发到达城市 �N 的最短时间。(到达城市 �N,不需要计算城市 �N 的隔离时间)

输入输出样例

输入 #1复制

4 4
5 7 3 4
1 2 4
1 3 5
2 4 3
3 4 5

输出 #1复制

13

说明/提示

【样例说明】

【评测用例规模与约定】

对于 100%100% 的数据, 1≤�≤1000,1≤�≤10000,1≤��≤200,1≤�,�≤1≤N≤1000,1≤M≤10000,1≤Ci​≤200,1≤u,v≤ �,1≤�≤1000N,1≤c≤1000

Dijkstra算法:

主要是利用邻接表和优先队列实现,总复杂度是O(nlongn)

实现:起点先入队,然后找到所有的邻居入队(除了已经标记了找到最短路的),找后序点的时候,优先选择路径短的点(用优先队列实现)

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3f
const int N=20010;
int n,m;
int t[N],dist[N];
struct edge{int to;int w;edge(int a,int b) {to=a;w=b;}	
};
vector<edge>e[N];
struct node{int id;int n_dis;node(int aa,int bb){id=aa;n_dis=bb;}bool operator < (const node& a)const{return n_dis > a.n_dis;}
};
void dijkstra(){bool done[N];	//标记数组,用于确定是否该节点找到最短路径 for (int i=1;i<=n;++i){done[i]=false;dist[i]=INF;}dist[1]=0;	//初始化,起点到起点的距离为0 priority_queue<node>q;q.push(node(1,dist[1]));while (!q.empty()){node p=q.top(); q.pop();if (done[p.id]) continue;done[p.id]=true;for (int i=0;i<e[p.id].size();++i){int y=e[p.id][i].to;int w=e[p.id][i].w;if (done[y]) continue;int res=t[y];if (y==n) res=0;if (dist[y]> p.n_dis+w+res){	//当前节点y到起点的最短路径大于路过p点到y点的路径 dist[y]=p.n_dis+w+res;q.push(node(y,dist[y]));}}}
}
signed main(){cin>>n>>m;for (int i=1;i<=n;++i) cin>>t[i];for (int i=0;i<m;++i){	//建立邻接表 int a,b,c;cin>>a>>b>>c;e[a].push_back(edge(b,c));e[b].push_back(edge(a,c));}dijkstra();cout<<dist[n];
} 

Bleeman—ford算法:

复杂度的是O(n^2),相比与floyd算法,该算法主要是找相邻节点,每一轮操作会找到一个最短路径的点,由于有n个点,所以需要进行n次,然后每次需要遍历所有的边。

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
int INF=0x3f3f3f3f;
const int N=20010;
int t[N],dist[N];
struct edge{int a;int b;int c;
}e[N];
signed main(){int n,m;cin>>n>>m;for (int i=1;i<=n;++i) cin>>t[i];for (int i=0;i<m;++i){int a,b,c;cin>>a>>b>>c;e[i].a=a,e[i].b=b,e[i].c=c;e[i+m].a=b,e[i+m].b=a,e[i+m].c=c;}memset(dist,INF,sizeof(dist));dist[1]=0;for (int k=1;k<=n;++k){	for (int i=0;i<2*m;++i){	//双向的 int u=e[i].a,v=e[i].b;int res=t[v];if (v==n)res=0;dist[v]=min(dist[v],dist[u]+res+e[i].c);	}}cout<<dist[n];
} 

SPFA算法:算法复杂度和Dijkstra一样,但是在最坏的情况下会达到O(n^2)是Bleeman—ford的优化,只更新上一轮有变化的点,不更新所有的点

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3f
const int N=20010;
int n,m;
int t[N],dist[N];
struct edge{int to;int w;edge(int a,int b) {to=a;w=b;}	
};
vector<edge>e[N];
int inq[N];	//判断是否在队列内 
void spfa(){memset(dist,INF,sizeof(dist));dist[1]=0;queue<int>q;	//队列内存放的是节点号 q.push(1);inq[1]=1;while (!q.empty()){int u=q.front(); q.pop();inq[u]=0;for (int i=0;i<e[u].size();++i){int v=e[u][i].to;int w=e[u][i].w;int res=t[v];if (v==n) res=0;if (dist[v]>res+dist[u]+w){		//只处理更新的节点 dist[v] =dist[u]+w+res;if (!inq[v]){inq[v]=1;q.push(v);}}}}
}
signed main(){cin>>n>>m;for (int i=1;i<=n;++i) cin>>t[i];for (int i=0;i<m;++i){int a,b,c;cin>>a>>b>>c;e[a].push_back(edge(b,c));e[b].push_back(edge(a,c));}spfa();cout<<dist[n];
} 

最小生成树:

最小生成树https://www.luogu.com.cn/problem/P3366

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz

输入格式

第一行包含两个整数 �,�N,M,表示该图共有 �N 个结点和 �M 条无向边。

接下来 �M 行每行包含三个整数 ��,��,��Xi​,Yi​,Zi​,表示有一条长度为 ��Zi​ 的无向边连接结点 ��,��Xi​,Yi​。

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

输入输出样例

输入 #1复制

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

输出 #1复制

7

说明/提示

数据规模:

对于 20%20% 的数据,�≤5N≤5,�≤20M≤20。

对于 40%40% 的数据,�≤50N≤50,�≤2500M≤2500。

对于 70%70% 的数据,�≤500N≤500,�≤104M≤104。

对于 100%100% 的数据:1≤�≤50001≤N≤5000,1≤�≤2×1051≤M≤2×105,1≤��≤1041≤Zi​≤104。

样例解释:

所以最小生成树的总边权为 2+2+3=72+2+3=7。

Prim算法和Kruskal算法的异同

同:都是利用贪心的方式

异:

Prim算法原理:“最小的邻居一定在树上”,从任意一个点u开始,把距离最近的v加入最小生成树中,下一步把距离{u,v}最近的w加入到树中,并且在生成的过程中保证不会生成环路,直到所有的点都在树上

代码与Dijkstra类似

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3fconst int N=4e5+5;
struct edge{int to;int w;edge(int a,int b){to=a;w=b;}
};
vector<edge>e[N];
int n,m,ans;
struct node{int id;int n_dis;	//区别在于Dijkstra这里存的是该节点到起点的最短距离,而Prim中存的是边长(该节点与其他邻居节点的最短边长) node(int a,int b): id(a),n_dis(b){}bool operator < (const node &a)const{return n_dis>a.n_dis;}
};
priority_queue<node>q;
bool done[N];
int dis[N];
void prim(){for (int i=1;i<=n;++i){done[i]=false;dis[i]=INF;}dis[1]=0;q.push(node(1,dis[1]));while (!q.empty()){node p=q.top(); q.pop();if (done[p.id]) continue;done[p.id]=true;ans+=dis[p.id];for (int i=0;i<e[p.id].size();++i){int  v=e[p.id][i].to;int  w=e[p.id][i].w;if (done[v]) continue;if (dis[v]> w){dis[v]=w;q.push(node(v,w));}}}for (int i=1;i<=n;++i){if (!done[i]){cout<<"orz";return;}}cout<<ans;return ;
}signed main(){cin>>n>>m;for (int i=0;i<m;++i){int a,b,c;cin>>a>>b>>c;e[a].push_back(edge(b,c));e[b].push_back(edge(a,c));}prim();
}

Kruskal算法原理:

“最短的边一定在最小生成树上”,从最短的边开始操作,以此加到树中。

算法步骤:先对所有的节点关系进行排序,然后依次把最小的边放到最小生成树中,其中对于是否成环(连通性问题)的判定,可以用并查集实现

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long
#define INF 0x3f3f3f3fconst int N=4e5+5;
int f[N]; 
struct edge{int from;int to;int dis;
};
edge e[N];
bool cmp(const edge& a,const edge& b){return a.dis<b.dis;
}
int find(int x){if (f[x]==x){return x;}else {f[x]=find(f[x]);return f[x];}
}
void unionn(int i,int j){f[find(i)]=find(j);
}
int n,m,ans,cnt;void Kruskal(){for (int i=1;i<=n;++i){f[i]=i;}sort(e+1,e+1+m,cmp);	//排序 for (int i=1;i<=m;++i){	//开始放边 if (find(e[i].from)!=find(e[i].to)){	//如果不会构成环 cnt++;	//节点就放到树上 ans+=e[i].dis;unionn(find(e[i].from),find(e[i].to));	//合并两个节点 }if (cnt==n-1)break;}if (cnt!=n-1) cout<<"orz";else if (cnt==n-1) cout<<ans;
}
signed main(){cin>>n>>m;for (int i=1;i<=m;++i){cin>>e[i].from>>e[i].to>>e[i].dis;}Kruskal();
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql8.0.36主从复制(读写分离)配置教程

1、关闭防火墙 使用命令行关闭防火墙 在Ubuntu系统中&#xff0c;可以使用以下命令关闭防火墙&#xff1a; sudo ufw disable执行该命令后&#xff0c;系统会提示是否要关闭防火墙&#xff0c;确认后即可关闭防火墙。 查看防火墙状态 使用以下命令可以查看防火墙当前的状…

React18原理: 时间分片技术选择

渲染1w个节点的不同方式 1 &#xff09;案例1&#xff1a;一次渲染1w个节点 <div idroot><div><script type"text/javascript">function randomHexColor() {return "#" ("0000" (Math.random() * 0x1000000 << 0).toS…

单片机学习笔记---DS18B20温度传感器

目录 DS18B20介绍 模拟温度传感器的基本结构 数字温度传感器的应用 引脚及应用电路 DS18B20的原理图 DS18B20内部结构框图 暂存器内部 单总线介绍 单总线电路规范 单总线时序结构 初始化 发送一位 发送一个字节 接收一位 接收一个字节 DS18B20操作流程 指令介…

OpenAI宣布ChatGPT新增记忆功能;谷歌AI助理Gemini应用登陆多地区

&#x1f989; AI新闻 &#x1f680; OpenAI宣布ChatGPT新增记忆功能&#xff0c;可以自由控制内存&#xff0c;提供个性化聊天和长期追踪服务 摘要&#xff1a;ChatGPT新增的记忆功能可以帮助AI模型记住用户的提问内容&#xff0c;并且可以自由控制其内存。这意味着用户不必…

【C++第二阶段】空指针访问成员函数常成员函数常成员属性

你好你好&#xff01; 以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 空指针访问成员函数常成员函数&常成员属性 空指针访问成员函数 类对象类型的空指针可以访问成员函数&#xff0c;但是不能够访问带有成员属性的成员函数。…

算法刷题:复写零

复写零 .习题链接题目描述算法原理初始值步骤1步骤2我的答案: . 习题链接 复写零 题目描述 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素…

【C++】内存详解(堆,栈,静态区)

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

【DDD】学习笔记-事件风暴与领域分析建模

在确定了全景事件流之后&#xff0c;可以在战略设计层面继续精进&#xff0c;鉴别出领域与限界上下文的边界&#xff0c;进入战术设计阶段的领域分析建模。 事件风暴的分析模型要素 通过事件风暴进行领域分析建模&#xff0c;其核心的模型要素就是“事件”。除此之外&#xf…

CUDA编程 - 共享内存 - shared memory - 学习记录

CUDA编程 - 共享内存 共享内存一、为什么要使用 shared memory&#xff1f;1.1、从硬件出发理解&#xff1a;1.2、从软件出发理解&#xff1a; 二、如何使用shared memory2.1、静态共享内存2.2、动态共享内存 三、实践 - 使用共享内存执行矩阵乘法总结 共享内存 一、为什么要使…

基于 Python 深度学习的电影评论情感分析系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

13. 【Linux教程】移动文件和目录

移动文件和目录 前面小节介绍了如何创建文件和目录、删除文件和目录&#xff0c;本小节介绍如何使用 mv 命令移动文件和目录。 1. 移动文件或目录至另外一个目录下 可以使用 mv file_name 路径 这种格式&#xff0c;移动文件至其他目录下&#xff0c;后面跟的路径可以是相对路…

政安晨:【详细解析】【用TensorFlow从头实现】一个机器学习的神经网络小示例【解构演绎】

准备工作 咱们将通过这篇文章反复咀嚼我原来文章里提到的那篇《神经网络小实例》&#xff0c;大家可以先看看&#xff0c;比如做些环境准备等等&#xff08;这是我的这篇文章的链接&#xff09;&#xff1a; 政安晨的机器学习笔记——基于Anaconda安装TensorFlow并尝试一个神…