算法乱谈

news/2025/10/4 18:58:27/文章来源:https://www.cnblogs.com/nytyq/p/19125827

1.图与树

  • 最短路

所谓最短路,在图上确定序列长度为 \(n\) 的序列 \(A\)\({P_1,P_2,...P_n}\),其中总有 \(P_i \rightarrow P_{i+1} \in E\),并且最小化 \(\sum_{i=1}^n W_{(P_i,P_{i+1})}\)

算法 1.dijkstra

其应用于非负权边。

考虑当前钦定点 \(i\) 拥有最短路,且为全局最小,那么我们更新任何 $ (i,j) \in E$ 之后的 \(i\) 的最短路便被锁定不可修改。

考虑其正确性:

假设 \(i\) 之后仍然有最短路将其更新,那么一定为祖先更新而来和儿子更新过来,我们定义祖先为算法流程中比 \(i\) 先更新的节点,儿子同理。容易发现之前的祖先已经被加算过,而此时儿子的 \(dis_j>dis_i+w_{(i,j)}\),其中 \(w>0\),那么再次更新一定不优,证毕。

朴素来讲时间 \(O(n^2)\),考虑求最小的步骤使用堆优化为 \(O(n \log m)\)

点击查看代码
#include"bits/stdc++.h"
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;int n,m,s;const int N=1e5+10,M=2e5+10;int h[N],e[M],ne[M],w[M],idx;void add(int a,int b,int c){e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}ll dist[N];
bool st[N];void dij(){memset(dist,0x3f,sizeof dist);dist[s]=0;priority_queue<pii,vector<pii>,greater<pii> >  q;q.push({0,s});while(q.size()){auto t = q.top();q.pop();int dis=t.first,ver=t.second;if(st[ver]) continue;st[ver]=1;for(int i=h[ver];~i;i=ne[i]){int j=e[i];if(dist[j]>dist[ver]+w[i]){dist[j]=dist[ver]+w[i];q.push({dist[j],j});}}}}int main(){memset(h,-1,sizeof h);cin>>n>>m>>s;while(m--){int a,b,c;cin>>a>>b>>c;add(a,b,c);}dij();for(int i=1;i<=n;i++){cout<<dist[i]<<" ";}return 0;
}

算法2.SPFA

虽然死力。

考虑拥有负权边的图上,其在更新结点之后不一定为最短,考虑更新 \(i\) 之后重置标记,并且如果当前点在队列中,我们考虑其不可被再次入队,因为一定不优。考虑入队次数,如果多次入队可判断负环。时间来说 \(O(n)\) 因为进队一次出对一次,但是严格卡的话 \(O(nm)\),别问怎么卡。

点击查看代码
int dist[N];
bool st[N];
void spfa(int s){queue<int> q;q.push(s);memset(dist,-0x3f,sizeof dist);memset(st,0,sizeof st);dist[s]=0;st[s]=1;while(!q.empty()){int x=q.front();q.pop();st[x]=0;for(int i=h[x];~i;i=ne[i]){int j=e[i];if(dist[j]<dist[x]+w[i]){dist[j]=dist[x]+w[i];if(!st[j]){st[j]=1;q.push(j);}}}}
}

3.Floyd

注意到前面的算法用于,考虑 \(f_{i,j}\) 表示 \(i\)\(j\) 的最短路,循环钦定 \(i \rightarrow k\)\(k \rightarrow j\) 即可。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define N 110
#define INF INT_MAX-2
int a[N][N];
int n,m;
void floyd(int x){for(int k=1;k<=n;k++){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(a[i][k]<INF&&a[k][j]<INF){a[i][j]=min(a[i][j],a[i][k]+a[k][j]);}}}} for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cout<<a[i][j]<<" ";}cout<<"\n";}
}
signed main(){ios::sync_with_stdio(false);cout.tie(nullptr);cin.tie(nullptr);int u,v,w;cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i==j)a[i][j]=0;else a[i][j]=INF;for(int i=1;i<=m;i++){cin>>u>>v>>w;a[u][v]=min(a[u][v],w);a[v][u]=min(a[v][u],w);}floyd(1);return 0;
}

2.最小生成树

详见最小生成树定义。

讨论最小生成树,我们容易想到一个朴素的贪心思想,使得最小生成树的权值总和最小。

在确定了选边顺序之后,考虑到如下情况:

  • \(i\) 条边是一个 \((u_i,v_i,w_i)\)的三元组描述一条边,表示 \(u_i\) 指向 \(v_i\),边权为 \(w_i\)
  • \(i+1\) 条边是一个 \((u_{i+1},v_{i+1},w_{i+1})\)的三元组描述一条边,表示如上。

正确性显然。

所以在我们选择 \(i+1\) 条边时,我们查找这个边的两个端点所在集合是否在同一个集合,如果是就不能加入,否则形成环。

思想如上。

例题

Agri-Net最短网络。

模板题,不赘述。

灌水

建立虚拟点,将单独的修建改为统一的操作。

丛林道路

模板题。

坏电工

模板题,最大生成树。

极地网络

考虑将所有的点相连建成完全图,注意建成的距离是平面欧氏距离计算,接着进行
Kruscal算法。

【Usaco Dec07 Silver】修建道路

如极地网络,略有不同。

【Usaco Nov08 Gold】安慰奶牛

包含了点权,考虑每一条边的所有总时间为端点安慰时间加上边权,接着进行Krucal算法。

南渝泼水节

非常简单,考虑合并两个集合,我们进行表示:

  • 集合一:\(F_1\) 描述祖先,\(S_1\) 描述大小。
  • 集合二同理。

则在描述的一条边 \((u,v,w)\) 连接两个上述集合,则我们要扩展为完全图,一共有要连 \(S_1 \times S_2 - 1\) 条边,考虑到保持最小生成树,则连得边的边长通为 \(w+1\)

点击查看代码
for(int i=1;i<n;i++){int fa=find(a[i].u),fb=find(a[i].v);if(fa!=fb){ans+=(size[fa]*size[fb]-1)*(a[i].w+1);f[fa]=fb;size[fb]+=size[fa]; }
}
cout<<ans<<endl;

Tree I

智力题,就是二分答案确定我们对白边的权值所改变的值,以此确定我们的白边数量每次趋近 \(need\) 条边。

3.最近公共祖先

引入

我们常常会遇到在一个家族中,两个人的祖辈是否相同,如果相同,最近的在那一辈。

对于这种情况,我们首先考虑到这个家族的关系图一定是一棵树,对于两个人我们就看做两个节点,求“两个人的祖辈是否相同,如果相同,最近的在那一辈”的问题,就是我们常说的 LCA,即 Lowest Common Ancestor 最近公共祖先。

倍增求 \(\text {LCA}\)

这种 LCA 求法是一种用 \(2\) 的幂次进行优化的暴力,下文简述,用 LCA 代替 倍增法求LCA。其是一种介于一维数组的稀疏表示与二维数组的稠密表示之间,其时间复杂度带有 \(\log n\),可优化成为 \(O(1)\),后文讨论。

LCA 和 RMQ问题 极度相识,其转态设计类似于 \(f_{u,i}\),表示 \(u\)\(2^i\) 级祖先。而在 RMQ 中的 \(f_{i,j}\) 表示 \(i\) 的后 \(2^j\) 个数的最大值或则和。

形式化的问题如下:

给定一颗静态树,树中两点 \(u,v\),求 \(\text{LCA}_{u,v}\)

我们考虑到同时查询,则先讲两个点提至同一深度,接着一起向上跳。

我们会发现,有的时候我们在调到一定深度时两个节点相同,便返回任意节点为其两个节点的 \(\text{LCA}\)

此处的调整高度主要采取倍增调整,但是要注意到倍增 \(\text{LCA}\) 有一种原则:先跨大步再跨小步。因为不一定在跨到下一步的时候,令节点的位置为 \(i\),则不一定保证 \(dep_i>dep_{\text {LCA}}\)

注意到代码中的 \(dep_u>dep_v\),其中 \(dep_i\)\(i\) 的深度。关于 \(f_{u,i}\) 的定义,详见前文。

伪代码:

点击查看代码
for(int i=log(dep[u]);i>=0;i--){if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
}

但是当深度相同时,我们不一定相等,则考虑到倍增向上跳,同样遵循“先大步再小步”,但注意我们求得是“最近公共祖先”,则在跳越查找的时候,有跳到 \(\text{LCA}_{u,v}\) 的更高级祖先的可能,于是为了处理,则我们在跳的时候,考虑下一步是否相等,如果相等则遇见刚才的情况,不跳,反之则跳。

伪代码:

点击查看代码
for(int i=log(dep[u]);i>=0;i--){if(fa[u][i]!=fa[v][i]){u=fa[u][i],v=fa[v][i];}
}
return f[u][0];//返回父亲节点,意思是我们最后完成//“相等则跳,不相等则不跳”的原则//则跳到的一定是 LCA 的儿子节点//此处易证

Tarjan 离线算法

以下内容源自 oi-wiki。

Tarjan 算法是一种离线算法,需要使用并查集记录某个结点的祖先结点。

做法如下:

  1. 首先接受输入边(邻接链表)、查询边(存储在另一个邻接链表内)。查询边其实是虚拟加上去的边,为了方便,每次输入查询边的时候,将这个边及其反向边都加入到 queryEdge 数组里。

  2. 然后对其进行一次 DFS 遍历,同时使用 visited 数组进行记录某个结点是否被访问过、parent 记录当前结点的父亲结点。

  3. 其中涉及到了回溯思想,我们每次遍历到某个结点的时候,认为这个结点的根结点就是它本身。让以这个结点为根节点的 DFS 全部遍历完毕了以后,再将这个结点的根节点设置为这个结点的父一级结点。

  4. 回溯的时候,如果以该节点为起点,queryEdge 查询边的另一个结点也恰好访问过了,则直接更新查询边的 LCA 结果。

最后输出结果。

性质:Tarjan算法需要初始化并查集,所以预处理的时间复杂度为 \(O(n)\)

欧拉序 求 \(\text{LCA}\)

时间复杂度 \(O(n\log n+m)\),其中 \(n\) 为节点个数,\(m\) 为查询次数。

欧拉序就是指访问到那个节点就加入欧拉序,一般都是 DFS 访问。

其实我们发现 LCA 就是在两点之间的树上最短路径上 \(dep\) 最浅的节点,答案显而易见,求 \(\text_{Euler}[pos[u],pos[v]]\) 中的深度最小值是谁,即 RMQ问题。

点击查看代码
const int N=1e5+10,M=2*N;int h[N],e[M],ne[M],w[M],idx;void add(int a,int b,int c){e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}int A[N<<1],sz;
int dep[N];
int pos[N];void dfs(int u,int fa){A[++sz]=u;pos[u]=sz;dep[u]=dep[fa]+1;for(int i=h[u];i;i=ne[i]){int v=e[i];if(v==fa) continue;dfs(v,u),A[++sz]=u;}
}int fa[N<<1][20],lg[N<<1];void init(){for(int i=1;i<=(n<<1);i++) fa[i][0]=A[i];for(int i=2;i<=(n<<1);i++) lg[i]=lg[i>>1]+1;for(int i=1;i<=lg[n<<1];i++){for(int j=1;j+(1<<i)-1<=(n<<1);j++){if(dep[fa[i][j-1]]<dep[fa[i+(1<<(j-1))][j-1]]){fa[i][j]=fa[i][j-1];} else fa[i][j]=fa[i+(1<<(j-1))][j-1];}}
}int get(int u,int v){if(pos[u]>pos[v]) swap(u,v);int Log=lg[pos[v]-pos[u]+1];if(dep[fa[pos[u]][Log]]<dep[fa[pos[v]-(1<<Log)+1][Log]]) return fa[pos[u]][Log];else return fa[pos[v]-(1<<Log)+1][Log]
}

DFS序求 \(\text {LCA}\)

定义:

这个是欧拉序的衍生版本(个人理解,长得比较像)。

优点:时间常数少一半,空间常数也少一半,吊打欧拉序。

先给一些定义:

  • DFS序:表示对一棵树进行深度优先搜索得到的结点序列

  • 时间戳DFN:表示每个结点在DFS序中的位置。

不妨设 \(dfn_u<dfn_v\)

结论:在DFS序的 \([dfn_u+1,dfn_v]\) 中的深度最浅的节点即为 \(\text {LCA}_{u,v}\)

证明:基本思想——分类讨论

  1. 如果 \(u\)\(v\) 不重链。

\(d=\text {LCA}_{u,v}\),则其访问顺序一定是 \(d-u-d-v\),那么 \(d\) 及的祖先一定不在 \([dfn_u,dfn_v]\),此处易证。

那么令 \(d\) 的儿子是 \(p\),则 \(p\) 一定存在与 \([dfn_u,dfn_v]\) 之间。

那我们只需要求 $$[dfn_u,dfn_v]$$ 之间深度最浅的节点,其父亲为 \(\text {LCA}_{u,v}\)

  1. 如果 u 和 v 重链。

将查询区间变为 \([dfn_u,dfn_v+1]\) 之间即可。

容易发现:\([dfn_u,dfn_v+1]\) 也适用于情况1。

查询:

点击查看代码
void add(int u,int v){g[u].push_back(v);}int get(int x,int y){return dfn[x]<dfn[y]?x:y;}void dfs(int u,int f){fa[dfn[u]=++dn][0]=f;for(auto it:g[u]) if(it!=f) dfs(it,u);
}int LCA(int u,int v){if(u==v) return u;u=dfn[u],v=dfn[v];if(u>v) swap(u,v);u++;int t=__lg(v-u);return get(fa[u][t],fa[v-(1<<t)+1][t]); 
}

预处理:

点击查看代码
for(int i=1;i<=__lg(n);i++){for(int j=1;j+(1<<i)-1<=n;j++){fa[i][j]=get(fa[i-1][j],fa[i-1][j+(1<<i-1)]);}
}

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

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

相关文章

2025 年 9 月习题集

2025年9月习题集P5933 [清华集训 2012] 串珠子。简单的图计数。 P8329 [ZJOI2022] 树。DP。 P6646 [CCO 2020] Shopping Plans。堆,最优化。 P7470 [NOI Online 2021 提高组] 岛屿探险。分治,01-Trie。 P4809 [CCC 2…

实用指南:Linux整个系统权限玩坏了怎么办

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

工业云网站建设为什么网站打开是空白

题意 给定两个人相互打电话&#xff0c;如果a打给b,b打给c,c打给a&#xff0c;则说a,b,c在同一电话圈中。给出n个人的m次通话&#xff0c;输出所有的电话圈 思路 用graph[u][v]1表示u和v之间有打电话。在使用floyd算法计算所有的点对之间的值。graph[u][v]1表示u,v之间有直接…

asp.net 网站开发 教程网页翻译器在线翻译

Amundsen 是一个用于数据发现和元数据管理的开源平台。Amundsen是一个用于提高数据分析师、数据科学家和工程师在与数据交互时的生产力的数据发现和元数据引擎。目前,它通过索引数据资源(表、仪表板、流等)并基于使用模式(例如,高频查询的表会比低频查询的表更早显示)提供…

做足球采集软件和预测软件的网站网站建设新闻发布注意什么

无向图概念时间戳\(dfn[x]\),在深度优先遍历中&#xff0c;按照每个节点第一次被访问的顺序&#xff0c;依次做整数标记追溯值\(low[x]\),通过非搜索边能到达的最小时间戳割边判定法则无向边\((x,y)\)是割边/桥&#xff0c;当且仅当存在x的一个子节点满足\(dfn[x] < low[y]\…

阐述网站建设的步骤过程网站首页成品

身为程序员哪一个瞬间让你最奔溃&#xff1f; 有一次我面临一个挑战&#xff0c;由于后续开发的需要&#xff0c;本来不需要同步块运行的部分突然需要进行同步块处理。为了避免重新设计同步块的耗时&#xff0c;我考虑使用一个资源占用标志代替。然而&#xff0c;事情并没有按…

Chrome 系统信息

Chrome 系统信息在地址栏中输入并访问​​ chrome://version/

YACS2025年9月甲组

YACS2025年9月甲组T1. 整除 创建一个由数对组成的数组 \(C\),其中每个元素为 \((i, a_i) \ (1 \leqslant i \leqslant n)\)。令 \(C_{x, 1}\) 和 \(C_{x_, 2}\) 分别表示数对 \(C_x\) 的第一个(即 \(i\))和第二个元…

信息链路层协议——以太网,ARP协议

信息链路层协议——以太网,ARP协议pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco…

微信小程序制作网站怎么让网站绑定域名访问

一般是kswapd0导致的cpu占用异常 按顺序执行以下操作 在控制台执行top命令&#xff0c;查看占用最高的是否kswapd0。基本100%占用。记下该进程ID 5081 执行查找命令 find / -name kswapd0 显示查找结果&#xff1a; /proc/3316/.X2c4-unix/.rsync/a/kswapd0 /root/.configrc…

关于网站开发的销售文章类网站后台

机试问题—实现基于BigDecimal的特殊的四舍五入。 这是一道外企的机试题&#xff0c;我把里面的某个难点部分&#xff0c;摘出来详细如下&#xff1a; //实现特殊的四舍五入&#xff0c;先普通四舍五入取到小数点后两位&#xff0c;然后最后一位向后进位&#xff0c;0和5不变&…

C# 代码规范

简单记录一下 C# 的代码规范。简单记录一下 C# 的代码规范。(不断更新…) 参考:.NET 编码约定 - C# | Microsoft Learn C# Coding Style例子 public class MagicClass { // 魔法类private int _magicNumber;public …

网站开发报价表的文档弧光之源网站建设

来源&#xff1a;36氪概要&#xff1a;波士顿动力公司的那只黄色机器人狗SpotMini&#xff0c;你还记得吗&#xff1f;波士顿动力公司的那只黄色机器人狗SpotMini&#xff0c;你还记得吗&#xff1f;它上一次亮相是在去年11月&#xff0c;当时它还在一片后院的草地上恣意奔跑。…

Docker 容器与镜像 - 实践

Docker 容器与镜像 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &…

实用指南:babelfish for postgresql 分析--todo

实用指南:babelfish for postgresql 分析--todopre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", …

MySql的存储过程以及JDBC实战 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

安徽合肥建设银行招聘网站万维网包括哪些网站

springboot745简历系统 获取源码——》公主号&#xff1a;计算机专业毕设大全

做外贸营销型网站浅谈博物馆网站建设意义

目录 基本查找*&#xff1a; 二分查找*&#xff1a; 数据单调递增&#xff1a; 数据单调递减&#xff1a; 总结规律&#xff1a; 插值查找*&#xff1a; 斐波那契查找&#xff08;了解原理&#xff09;&#xff1a;以后补 分块 查找*&#xff1a; 特殊 情况&#xff0…

深圳哪家做网站最好辽宁建设工程信息网ca锁激活

本文目录 本系列文章从新开始为啥要用TypeScript官方文档程序框架从package.json开始tsconfig.jsonJest的配置 jest.config.js服务的实现自动化测试setup.ts文件夹integration 执行及测试对应代码及branch 本系列文章 SAP CAP篇一: 快速创建一个Service&#xff0c;基于Java的…

阿里云万网域名关键词优化排名软件

1. Json 数据解析和绑定 客户端传参&#xff0c;后端接收并解析到结构体 package mainimport ("github.com/gin-gonic/gin""net/http" )// 定义接收数据的结构体 type Login struct {// binding:"required"修饰的字段&#xff0c;若接收为空值…