算法设计与分析:实验五 图论——桥问题

news2024/9/23 19:57:35

实验内容:

1. 桥的定义

在图论中,一条边被称为“桥”代表这条边一旦被删除,这张图的连通块数量会增加。等价地说,一条边是一座桥当且仅当这条边不在任何环上。一张图可以有零或多座桥。

2. 求解问题

找出一个无向图中所有的桥。

1.基准算法

(1)算法思路:

  • 遍历每条边:对于图中的每一条边 (u, v),逐条进行处理。
  • 移除边 (u, v):暂时从图中移除边 (u, v)。
  • 检查连通性:使用广度优先搜索(BFS)或深度优先搜索(DFS)检查移除边 (u, v) 后的图是否仍然连通。如果移除边 (u, v) 后,图变得不连通(即连通块的数量增加),则说明边 (u, v) 是一座桥。
  • 恢复边 (u, v):将边 (u, v) 加回到图中,恢复原始状态。
  • 重复上述步骤:对图中的每一条边重复上述步骤,最终找出所有的桥。

(2)伪代码:

基准算法

bool BFS(src,des,eidx) //BFS用来检查移除一条边后,图是否仍然连通

{

  Queue q  // 定义一个队列,用于广度优先搜索

  Vis[src]=true  // 标记起点为已访问

  For 枚举src的邻点j:

    If i>>1 != eidx-1:  //如果此边不是我们要删掉的就入队

      q.push(j),Vis[j]=1

  While(q.size()):  // 当队列不为空时,继续搜索

    u=q.front(),q.pop()  // 取出队首元素

    For 枚举u的邻点v:

      If v==d return True  //如果删掉src-des这条边,两个点还能连通则不是桥

      If !Vis[v]: Vis[v]=true,q.push(v)

  Return false;  // 如果搜索完毕仍未到达目标节点,返回 false,不连通

}

voids func0()  //找到图中的所有桥

{

  For i=1 to m: //枚举每条边

    u,v //u和v作为每条边的两个端点

    memset(Vis ,false,sizeof(Vis)) //每次删除每条边判连通都要初始化访问数组

    If !BFS(u,v,i):  //如果删掉i这条边后不连通则此条边为桥

    Ans++,edge[i].isbridge=true;

}

(3)时间复杂度:

对于每一条边 (u, v),需要执行一次 BFS,BFS会将所有的点和边遍历一遍,则最坏的时间复杂度为 O(n+m),其中n是顶点数,m是边数。由于需要对每一条边都进行一次这样的操作,算法的总时间复杂度为 O(m*(n+m))=O(m^2+nm)。对于稠密图,这样的复杂度是非常高的。基准算法尽管简单直接,但在实际应用中效率较低,因此通常使用更加优化的算法来降低复杂度。

2.优化算法--使用按秩合并及可撤销并查集

(1)算法分析:

  • 当我们处理图的连通性问题时,每次BFS都需要重新遍历所有的点,但删除或添加一条边后,实际上只有与这条边相关的部分需要重新检查,而不是整个图。这意味着我们可以利用一些数据结构来只处理变化部分,从而提高效率。
  • 使用并查集
  1. 并查集是一种高效处理连通性查询的树型数据结构,常用于处理一些不相交集合的合并及查询两个元素是否同属一个集合,支持快速的合并和查找操作。
  2. 并查集将所有点分成一个一个的集合,对每一个集合都设定一个父节点,集合内所有的点最终都会指向该父节点。因此通过检查两个点所在的集合的父节点是否相同,可以以较快的速度判断得到两个点是否处于同一个集合中,若相同则同属一个集合,若不同则不属同一个集合。
  3. 并查集有查找与合并两种操作:一是查询,查询当前两个元素是否在同一集合中;二是合并,将两个不在同一集合中的两个子集合合并为一个集合。

伪代码如下:

并查集基本操作

  1. int find (int x)  //查找当前元素所属集合的代表元/祖先结点
  2. {
  3.   If fa[x]==x: return x  //如果是本身就直接返回
  4.   Return fa[x]=find(fa[x])  //如果不是则继续递归向下找
  5. }
  6. void connect (int x,int y)  //合并两个元素/子集合
  7. {
  8.   Px=find(x) //找到x元素的祖先结点
  9.   Py=find(y) //找到y元素的祖先结点
  10.   If (Px==Py) return //如果两个元素已经属一个集合,就不进行操作
  11.   fa[Py]=Px  //进行合并
  12. }
  1. 标准的并查集在处理动态添加边时非常高效,但不能处理删除边的情况。
  2. 并查集判断一条边是不是割边:去掉一条边后,使用并查集快速查看此边的两个端点是否在同一个集合(即是否可以相互到达),如果是则不是割边,否则是割边。
  • 并查集合并操作采用按秩合并

  1. 在并查集结构中,每个集合都有一个属性称为rank(秩),代表了以该集合根节点为根的树的高度或近似高度。
  2. 按秩合并指的是在合并两个集合时,总是将秩较小的树的根节点指向秩较大的树的根节点。尽可能地减少树的高度增长,保持树的平衡,进而优化查找操作的效率
  3. 在并查集中,秩的初始值为0。当两个秩相同的树合并时,新的根节点的秩增加1。如下图所示,如果按秩合并将A集合合并到D集合,不难发现,合并后的层数依旧是三层;如果将D合并到A上,那么深度就会变成四层。多一层子节点的搜索就会变多,按秩合并就是通过减少层数来减少搜索次数,从而优化时间复杂度。
  4. 路径压缩防止不平衡状态:如果并查集是左边这种形式那么搜索后面的元素那么就会需要O(n)的复杂度,如果所有的元素全部搜索那么就会达到O(n^2)的复杂度。所以采取按秩合并的方法,合并后的形式,这样搜索每一个元素所需时间复杂度为O(1)。
  5. 按秩合并的过程:
  • 每个节点在初始状态下都是一个单独的集合,rk 为 0。
  • 当两个集合进行合并操作时,根据它们的秩进行合并:如果待合并的两个集合的 秩不同,将秩较小的集合合并到秩较大的集合中,这样不会增加整体树的高度。如果待合并的两个集合的秩相同,则任意选择一个作为新的根节点,但需要将秩加 1,以保持整体平衡。

 在这种优化策略下,操作的时间复杂度能够保持在 O(logm),其中 m 是操作次数。

  • 使用支持删除操作的可撤销并查集

  1. 为了处理删除边的情况,可以使用可撤销并查集。通过记录操作的历史,我们可以在需要时回滚操作,恢复之前的状态。这使得我们可以高效处理边的删除和添加。
  2. 考虑使用栈存储并查集合并时修改的信息。撤销的操作遵循栈后进先出的规律。如果要撤销合并操作,可以将栈中的数据弹出,进行数据复原便完成了合并操作撤销。

(2)算法思路:

  1. 先判断第一条边是不是割边。将除第一条边外的所有边,按照边序号从后到前遍历,将边连接的两个点进行并查集的合并操作。然后查询第一条边连接的两个点是否在一个集合里。
  2. 然后判断第二条边是不是割边。撤销并查集对第二条边的修改。将第一条边连接的两个点进行合并。并查集查询第二条边连接的两个点是否在一个集合里。
  3. 然后判断第三条边是不是割边,撤销并查集对第一三条边的修改。将第一第二条边里连接的两个点进行合并。并查集查询第二条边连接的两个点是否在一个集合里。
  4. 以此类推可以通过并查集判断第四条边是不是割边直到最后一条边是不是割边。

(3)伪代码:

优化算法--使用按秩合并及可撤销并查集

  1. void connect( u , v )  //按秩合并
  2. {
  3.   Pu=find(u),Pv=find(v)  //Pu和Pv为两个元素各自所在集合的根节点
  4.   If Pu==Pv: return  //不用合并
  5.   If rk[Pu]<rk[Pv]: stack[++sp]=Node(Pv,Pu,rk[Pv])  //Pu指向Pv,秩为Pv的秩
  6.   Else stack[++sp]=Node(Pu,Pv,rk[Pu])  //Pv指向Pu,秩为Pu的秩
  7.   If rk[Pu]<rk[Pv]: fa[Pu]=Pv  //秩小的根节点指向秩大的根节点
  8.   Else if rk[Pu]==rk[Pv]: fa[Pv]=Pu,rk[Pu]++;
  9.   Else fa[Pv]=Pu
  10. }
  11. void Pop(size) //撤销操作
  12. {
  13.   Node temp;
  14.   While(sp>size):
  15.     Temp=stack[sp--]  //取出栈顶元素
  16.     rk[temp.u]=temp.rk  //恢复秩
  17.     fa[temp.v]=temp.v   //恢复父节点
  18. }
  19. void Check() //遍历每条边
  20. {
  21.   For i from 1 to m:
  22.     u=edge[i].u, v=edge[i].v
  23.     int size=sp;  //记录当前栈顶位置
  24.     For j from m to 1 dec:  //合并除当前边以外的所有边
  25.       If i==j: continue  
  26.       connect(edge[j].u,edge[j].v)
  27.     If find(u)!=find(v):  //如果当前边两个点不在同一个集合即当前边是桥
  28.       edge[i].isbridge=true,ans++;
  29.     Pop(size)  //撤销操作
  30. }
  31. Int func1()
  32. {
  33.   For i from 1 to n:
  34.     fa[i]=i, rk[i]=0  //并查集初始化操作
  35.   sp=0  //栈顶指针初始为0
  36.   Check()
  37. }

(4)时间复杂度:

  1. 合并除当前边以外的所有边:内层循环遍历所有边,除去当前边,时间复杂度是 O(m)。在按秩合并的并查集操作时间复杂度是O(logm)。总的来说,内层循环的时间复杂度是 O(m*logm)。
  2. 撤销操作:Pop(siz); 的时间复杂度取决于操作数量。在最坏情况下,需要撤销所有的合并操作,时间复杂度是 O(m)。
  3. 因此,Check 函数中每次外层循环的时间复杂度是:O(m*logm)。由于外层循环执行 m 次,总时间复杂度是:O(m^2*logm)
  4. 包括初始化的时间复杂度,总的时间复杂度是:O(n+m^2*logm)
  5. 因此总的时间复杂度为:O(m^2*logm)对于边数 m 非常大的图,性能会下降。

3.优化算法--使用可撤销并查集+线段树分治

(1)算法分析:

在使用可撤销并查集判断割边时,每条边都需要通过多次的合并和撤销操作来确定是否是割边。原始方法是逐条边处理,每处理一条边,需要撤销前面所有边的合并操作,这样会导致前面的边在栈中频繁弹入弹出,而后面的边基本没有太多操作。因此,整体效率较低。因此可以利用线段树的分治思想来优化这个过程,使得整体的弹入弹出次数降低。具体来说,通过分治的方式将问题分成多个子问题,解决子问题时可以一次性处理一个区域的边,减少频繁的单条边操作。使用线段树分治优化栈的弹出弹入方法。可以连续弹入或弹出一片区域中的边。

  1. 线段树:线段树是一种二叉搜索树 。它将一段区间划分为若干单位区间 ,每一个节点都储存着一个区间。线段树支持区间求和,区间最大值,区间修改,单点修改等操作。线段树的思想和分治思想很相像。对边进行编号划分,得到所有的边按序排好作为一个区间标记为一号节点,然后将前面一半的边作为一个区间标记为二号节点,将后面一半的边作为一个区间标记为三号节点,以此类推,得到下图所示的线段树结构。当查询到下图箭头所指区域时,其他边(绿色块)都处于被压入栈的情况,并且深度越大的绿色块,在栈中的高度越高
  2. 利用线段树优化查询:实际运行中,会以深搜的方法遍历每一个叶子节点,而每一个叶子节点就对应一条边,比如以上图为例,首先会经过1,2,4号节点到达8号结点,找到第1号边;然后回溯到4号节点,再来到9号节点,找到第2号边;然后再回溯到4号节点和2号节点,进入5号节点和10号节点,找到第3号边。以此类推。查询完橙色的4号边之后,要查询5号边,首先根据深搜的顺序,回溯到1号节点,途中将10,4,3号节点所囊括的边全部弹出栈中,然后进入3号节点,进入3号节点前,先将2号节点囊括的边压入栈中,然后进入6号节点,进入6号节点前,先将7号节点所囊括的边压入栈中,最后进入12号节点,进入12号节点前,将13号节点所囊括的边压入栈中,得到此时仅剩12号节点对应的5号边没有连接。如果后面要查询6号边操作同理,过程如下图表所示(从上到下从左到右):


再使用并查集查询某边连接的两个点是否在用一个集合,以此来判断此边是否为割边。以此类推遍历每一个叶节点的边就可以完成查询所有边是否为割边(即是否为桥)。

(2)算法实现思路:

  1. 对于每个区间 [l, r],如果区间只有一条边,则直接判断是否为桥边。
  2. 否则,递归处理右半部分 [mid+1, r],合并区间内所有边,再递归处理左半部分 [l, mid],最后撤销合并操作。
  3. 通过分治递归,有效减少了频繁的栈操作,提高了整体的处理效率。

(3)伪代码:

优化算法--使用按秩合并及可撤销并查集+线段树分治

  1. void Push(l , r)
  2. {  //将编号为l到r的边进行合并
  3.   For i from r to l dec:
  4.     connect(edge[i].u,edge[i].v)
  5. }
  6. void DFS(l , r)  //递归函数
  7. {
  8.   If l==r : //基本情况,区间只有一条边,直接判断
  9.     If find(edge[l].u)!=find(edge[l].v) : //如果不连通则是桥
  10.       edge[l].isbridge=true,ans++
  11.     Return
  12.   size=sp  //保存当前栈顶位置
  13.   mid=(l+r)>>1
  14.   Push(mid+1,r) //处理右半部分
  15.   DFS(l,mid)
  16.   Pop(size) //撤销右半部分的合并操作
  17.   Push(l,mid) //处理左半部分
  18.   DFS(mid+1,r)
  19.   Pop(size) //撤销左半部分的合并操作
  20. }
  21. Int func2()
  22. {
  23.   For i from 1 to n:
  24.     fa[i]=i, rk[i]=0  //并查集初始化操作
  25.   sp=0  //栈顶指针初始为0
  26.   DFS(1,m)
  27. }

(4)时间复杂度:

  1. 在按秩合并的可撤销并查集操作时间复杂度下降为O(logm)。
  2. 在线段树分治中,递归深度为O(logm),每次递归中调用Push和Pop操作,分别处理两个子区间,合并和撤销的边数最多为O(m),即为O(mlogm)
  3. 因此,总的时间复杂度为O(m*(logm)^2)
  4. 此外,并查集的操作实际上很多时候并不会到达O(logm)的时间复杂度,所以总体而言这个时间复杂度还是比较不错的。

4.拓展:Tarjan算法验证并查集优化+线段树分治的算法正确性

使用 Tarjan 算法找到所有的桥边后,可以与并查集优化+线段树分治算法优化的结果进行比较,验证两者是否一致。若一致,说明线并查集优化+线段树分治的方法正确无误。

Tarjan算法:通过深度优先搜索(DFS)结合时间戳和回溯时间戳来判断一个边是否是桥边。算法的时间复杂度是O(n+m),其中n是节点数,m是边数。

Tarjan算法思路:

 1.初始化:将 dfn (用于存储每个节点的首次访问时间戳)和 low(用于存储节点的回溯时间戳,即当前节点或其子树能够回溯到的最早的祖先节点的时间戳) 数组清零。初始化时间戳 tstp 为0。

2.遍历所有节点:对每个节点,如果还没有被访问过(即 dfn[i] == 0),调用 tarjan 函数从该节点开始进行DFS。

3.DFS过程:遍历所有邻接节点 v,如果 v 未被访问过,递归调用 tarjan,更新 low[u]。如果 dfn[u] < low[v],说明 u-v 是桥边。如果 v 已被访问,且不是通过父边返回,更新 low[u]。

Tarjan算法伪代码:

Tarjan算法

  1. Int dfn[MAXN],low[MAXN],tstp=0
  2. void tarjan(u , pre)
  3. {
  4.   dfn[u]=low[u]=++tstp //初始化dfn和low
  5.   For 枚举u的邻点v:
  6.     If !dfn[v]://如果v未被访问
  7.       tarjan(v,i)  //递归访问v
  8.       low[u]=min(low[u],low[v])  //更新low[u]
  9.       If dfn[u]<low[v]://判断是否为桥边,如果dfn[u]<low[v]则是桥边
  10.         edge[i/2+1].isbridge=true,ans++
  11.     Else if (i!=(pre^1))://更新low[u](忽略父边)
  12.       low[u]=min(low[u],dfn[v])
  13. }
  14. Int func3()
  15. {
  16.   For i from 1 to n:
  17.     dfn[i]=low[i]=0  
  18.   tstp=0  
  19.   For i from 0 to n-1:
  20.     If !dfn[i]:tarjan( i , -1)
  21. }

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

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

相关文章

用MATLAB 画一个64QAM的星座图

由于QAM采用幅度和相位二维调制&#xff0c;其频谱效率大大提高&#xff0c;而且不同点的欧式距离也要大于调幅AM调制方式&#xff0c;QAM也是LTE和5G NR首选的调制方式&#xff0c;本期教大家画一个64QAM的星座图。 如下&#xff1a; 首先产生一个64QAM的调制数据&#xff0…

18044 成绩等级评分

### 思路 1. 从键盘输入一个整数成绩。 2. 判断成绩是否在0到100之间&#xff1a; - 如果不在范围内&#xff0c;输出“error”。 - 如果在范围内&#xff0c;根据成绩范围输出对应的等级&#xff1a; - 90分以上为A - 80到89分为B - 70到79分为C - …

数仓架构:离线数仓、实时数仓Lambda和Kappa、湖仓一体数据湖

往期推荐 大数据HBase图文简介-CSDN博客 数仓分层ODS、DWD、DWM、DWS、DIM、DM、ADS-CSDN博客 数仓常见名词解析和名词之间的关系-CSDN博客 目录 往期推荐 1. 数仓架构 1.1 离线数仓架构 1.1.1 数据集市架构 1.1.1.2 独立数据集市 1.1.1.2 从属数据集市 1.1.2 Inmon企…

Java的线程池简述

线程池的工作原理 线程池是为了减少频繁的创建线程和销毁线程带来的性能损耗&#xff0c;线程池的工作原理如下图&#xff1a; 线程池分为核心线程池&#xff0c;线程池的最大容量&#xff0c;还有等待任务的队列&#xff0c;提交一个任务&#xff0c;如果核心线程没有满&…

基于SpringBoot+Vue+MySQL的宠物寄养服务管理系统

系统背景 互联网社会的到来&#xff0c;让各行各业通过互联网实现了浴火重生的可能&#xff0c;每个行业都发现了完全可以使用互联网技术用来提高信息在内部的传递效率&#xff0c;提高管理水准。通过本次对宠物寄养服务系统的设计和开发&#xff0c;不仅能巩固已经学到的知识&…

代码随想录 刷题记录-22 动态规划(6)习题

1.300.最长递增子序列 子序列问题是动态规划解决的经典问题&#xff0c;当前下标i的递增子序列长度&#xff0c;其实和i之前的下标j的子序列长度有关系. 动规五部曲&#xff1a; 1.dp数组及下标含义 dp[i] : 从任意位置开始&#xff0c;以nums[i]元素作为结尾的所有 递增子…

Unity编辑器开发 Immediate Mode GUI (IMGUI)

1. 简介&#xff1a; IMGUI是代码驱动gui系统&#xff0c;由 OnGUI 函数驱动&#xff1a; void OnGUI() {if (GUILayout.Button("Press Me")){ Debug.Log("Hello!");} } IMGUI常用于&#xff1a; 创建 in-game debugging displays and tools&#xff1b…

Redis基础命令和事务,redis持久化和主从复制

目录 第一章、Redis数据库的下载和安装1.1&#xff09;nosql数据库和 Redis 介绍1.2&#xff09;Windows中下载安装Redis数据库1.3&#xff09;Linux中安装Redis数据库1.4&#xff09;Linux中启动redis1.5&#xff09;Linux中关闭redis 第二章、三种Redis客户端连接Redis数据库…

AI安全立法:加州新法案的争议与未来影响

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

版本管理工具 Git 的下载安装及使用

1 基本介绍 Git 是目前最流行的分布式版本控制软件 什么是分布式版本控制软件&#xff1f; 所有版本信息仓库全部同步到本地的每个用户可以在本地查看所有版本历史&#xff0c;可以离线在本地提交&#xff0c;只需在连网时 push 到相应的服务器或其他用户那里。每个用户那里…

一键翻译全球:2024年跨文化交流的得力助手

翻译工具作为沟通不不同语言桥梁上的重要使者&#xff0c;正在从古老的字典查阅到现代的机器翻译软件发展。今天&#xff0c;让我们一同探索与搜狗翻译工具相似的翻译工具们怎么带我们走进奇妙世界。 1.福晰翻译 链接直达>>https://www.foxitsoftware.cn/fanyi/ 这款多…

数字芯片中I/O单元及电源domain布局中SIPI的考虑

芯片设计的物理实施过程通常也简称为布局布线&#xff08;P&R&#xff0c;Place-and-Route&#xff09;&#xff0c;布局一般被分为布局规划&#xff08;Floorplan&#xff09;和标准单元摆放&#xff08;Place&#xff09;两个过程。而其中的布局规划是芯片后端物理实现过…

用Starbound星际边界服务器开服联机

1、登录服务器&#xff08;百度莱卡云游戏面板&#xff09; 进入控制面板后会出现正在安装的界面&#xff0c;安装大约10分钟&#xff08;如长时间处于安装中请联系我们的客服人员&#xff09; 2、连接游戏 开机后等待服务器地址下方正常运行时间的表由黄色变成灰色并且在计时…

Centos7.x安装grafana11

第一步&#xff1a;yum安装 sudo yum install -y https://dl.grafana.com/enterprise/release/grafana-enterprise-11.2.0-1.x86_64.rpm 第二步&#xff1a;改成中文 vim /etc/grafana/grafana.ini 第三步&#xff1a;启动 systemctl start grafana-server 第四步&#x…

linux文件——文件系统——学习、理解、应用软硬件链接

前言:本篇内容主要讲解文件系统的软硬件链接。 经过前两篇文件系统的文章——讲解硬件&#xff08;磁盘&#xff09;、讲解文件系统底层&#xff0c; inode&#xff0c; 我们本节内容可以很好的理解我们要讲解的内容。 并且本节内容较少&#xff0c; 友友们学习本节的时候将会比…

Linux(CentOS 7)

Linux(CentOS 7) super space : 切换输入法 ctrl alt : 级别三(大黑屏)呼出鼠标 Fn Ctrl Alt F1 : 进入图形化界面 Fn Ctrl Alt F2 : 进入控制台界面 第 1 章 Linux 入门 1.1 概述 Linux是一个操作系统(OS) 1.2 Linux 和 Windows 区别 第 2 章 VM 与 Linux 的安装…

Apache Paimon:开启实时湖仓存储新时代

Apache Paimon&#xff1a;开启实时湖仓存储新时代 前言Apache Paimon 前言 在当今数字化浪潮汹涌澎湃的时代&#xff0c;数据已成为企业最为宝贵的资产之一。如何高效地处理、存储和利用这些海量数据&#xff0c;成为了企业在激烈竞争中脱颖而出的关键。而在数据处理的广阔领…

rsyslog交叉编译(armv7、armv8、aarch64、arm32平台通用)

文章目录 1、依赖库列表2、编译建议3、编译3.1、编译libestr3.2、编译libfastjson3.3、编译zlib3.4、编译libuuid3.5、编译libgpg-error3.6、编译libgcrypt3.7、编译openssl3.8、编译curl3.9、编译rsyslog该文档描述了如何交叉编译rsyslog到arm64嵌入式平台。 1、依赖库列表 li…

openjudge- 4.6算法之贪心_8469:特殊密码锁

题目 8469:特殊密码锁 总时间限制: 1000ms 内存限制: 1024kB 描述 有一种特殊的二进制密码锁&#xff0c;由n个相连的按钮组成&#xff08;n<30&#xff09;&#xff0c;按钮有凹/凸两种状态&#xff0c;用手按按钮会改变其状态。 然而让人头疼的是&#xff0c;当你按一个…

c++140namespace和ioterm

c语言只有一个全局定义域 那么可能会调错函数&#xff0c;调 错定义域 #include"iostream" using namespace std;//iostream 没有引入标准的std,需要手工写 //如果不写using namespace 需要引入std void main() {std::cout << "using test" <<…