• 关于求图的拓扑排序问题之bfs


    关注 码龄 粉丝数 原力等级 -- 被采纳 被点赞 采纳率 最幸运的小孩(ง •̀_•́)ง 2024-04-21 15:49 采纳率: 0% 浏览 1 首页/ 编程语言 / 关于求图的拓扑排序问题之bfs c++宽度优先 关于求图的拓扑排序问题之bfs ```c++ #include #include using namespace std; const int N=1e5+10; int h[N],e[N],ne[N],idex,n,m,q[N],d[N]; void add(int a,int b){ e[idex]=b; ne[idex]=h[a]; h[a]=idex; idex++; } bool topsort(){ int hh=0,tt=-1; for(int i=1;i<=n;i++){ if(!d[i]) q[++tt]=i; } while(hh<=tt){ //首先拿出队头元素 int t=q[hh++]; //进行拓展 for(int i=h[t];i!=-1;i=ne[i]){ int j=e[i]; if(--d[j]==0) q[++tt]=j; } } //检查进队了多少个元素 return tt==n-1; } int main(){ cin>>n>>m; memset(h,-1,sizeof(h)); while(m--){ int x,y; cin>>x>>y; add(x,y); d[y]++; } if(topsort()){ for(int i=0;i

    4条回答 默认 最新

    • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-21 15:49
      关注

      引自免费微信小程序:皆我百晓生

      在原始代码中,if(--d[j]==0) 的写法实际上是在递减 d[j] 的同时检查其是否为零。这样做的问题是,在某些情况下可能会导致节点被错误地添加到拓扑排序序列中,尤其是在存在环路的情况下。

      当我们将这段代码修改为:

      for(int i=h[t];i!=-1;i=ne[i]){
          int j=e[i];
          if(!d[j]) d[j]--;
          if(d[j]==0) q[++tt]=j;
      }
      

      这里,我们先检查 d[j] 是否为零,然后再递减它。这个改动使得我们只会在 d[j] 非零时才递减它。这样做的好处是可以确保在处理有向图中的环路时,不会错误地添加环内的节点到拓扑排序序列中,因为环内所有节点的入度永远不会变为零。

      然而,这个改动并不能解决所有情况下的拓扑排序问题,尤其是对于存在环路的情况。如果图中有环,那么在任何情况下,环内的节点都无法进行拓扑排序,因为它们的入度永远不可能降为零。因此,我们需要一个额外的方法来检测环路并返回错误信息。

      以下是修复后的代码,包括了一个简单的环路检测方法:

      #include
      #include
      using namespace std;
      const int N=1e5+10;
      int h[N],e[N],ne[N],idex,n,m,q[N],d[N],vis[N];
      
      // 新增函数用于检测环路
      bool hasCycleUtil(int node, bool visited[], int parent){
          visited[node] = true;
          
          for(int i = h[node]; i != -1; i = ne[i]){
              int adj = e[i];
              
              if(!visited[adj]){
                  if(hasCycleUtil(adj, visited, node)) return true;
              }
              else if(parent != adj) // 如果找到回边,则表示有环
                  return true;
          }
          return false;
      }
      
      bool hasCycle(){
          bool visited[N] = {false};
          for(int i = 1; i <= n; ++i){
              if(!visited[i] && hasCycleUtil(i, visited, -1))
                  return true;
          }
          return false;
      }
      
      bool topsort(){
          int hh=0,tt=-1;
          for(int i=1;i<=n;i++){
              if(!d[i]) q[++tt]=i;
          }
          while(hh<=tt){
              // 首先拿出队头元素
              int t=q[hh++];
              // 进行拓展
              for(int i=h[t];i!=-1;i=ne[i]){
                  int j=e[i];
                  
                  if(!d[j]) d[j]--;
                  if(d[j]==0) q[++tt]=j;
              } 
          }
          // 检查进队了多少个元素,并且检测是否有环
          return tt==n-1 && !hasCycle();
      }
      
      int main(){
          cin>>n>>m;
          memset(h,-1,sizeof(h));
          while(m--){
              int x,y;
              cin>>x>>y;
              add(x,y);
              d[y]++;
          }
          if(topsort()){
              for(int i=0;i

      在这个版本中,我增加了 hasCycleUtil() 函数,这是一个深度优先搜索(DFS)辅助函数,用于检测图中是否存在环。另外,我还添加了 hasCycle() 函数,它会遍历每个未访问过的节点,调用 hasCycleUtil() 来检测环路。如果检测到环路,hasCycle() 将返回 true。在 topsort() 函数中,我们在计算拓扑排序后检查是否有环,如果有则返回 false。这样,即使在存在环路的情况下,程序也能正确地返回 -1

      展开全部

      评论 编辑记录
    • Kwan的解忧杂货铺 Java领域优质创作者 2024-04-21 15:49
      关注

      下午好🌅🌅🌅
      本答案参考ChatGPT-3.5

      首先,这两段代码的本质是一样的,差别只存在一点细节上。具体讲,第一个代码中,我们对 $d_j$ 直接减 $1$,并且只在 $d_j$ 被减到 $0$ 时将其入队;而第二个代码中,我们先判断 $d_j$ 是否为 $0$,再将 $d_j$ 减 $1$,并将其入队。

      但是,根据拓扑排序的原理,当我们发现某个点 $u$ 的入度为 $0$ 时,为了保证拓扑序的唯一性,我们应该立即将其出队,并对其指向的所有点的入度减一。而上述第二个代码中的判断 $d_j$ 是否为 $0$ 会影响到此时的入队顺序,从而导致程序结果错误。

      综上所述,应按照第一个代码的写法进行修改。

      修改代码如下:

      for (int i = h[t]; i != -1; i = ne[i]) {
          int j = e[i];
          if (--d[j] == 0) q[++tt] = j;
      }
      

      提示:在进行队列操作时,建议使用标准队列 STL 中的 queue,具有更好的可读性和逻辑性。

      评论
    • 码农阿豪 Java领域优质创作者 2024-04-21 15:49
      关注
      让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
      问题分析: 以上代码是进行拓扑排序的BFS算法实现。拓扑排序的过程是对有向图中的所有节点进行排序,使得对于任何一条有向边 (u, v),都有u排在v的前面。拓扑排序可以用于检测有向图中的环,如果有环则无法进行拓扑排序。 在以上代码中,出现错误的地方是在for循环中,将原先的if(--d[j] == 0)修改为if(!d[j]) d[j]--,这样的修改会导致拓扑排序得到错误的结果。 具体分析修改后的代码如下: for(int i=h[t]; i!=-1; i=ne[i]){
      int j = e[i];
      if(!d[j]) d[j]--; // 将原先的--d[j] == 0修改为!d[j] d[j]--
      if(d[j] == 0) q[++tt] = j;
      

      } 在原先的代码中,if(--d[j] == 0)表示将节点j的入度减1,并判断减1后的入度是否为0,如果为0则将节点j加入队列中。而修改后的代码中,if(!d[j])表示如果节点j的入度为0,则将其入度减1。这样的修改会导致在入度为0的节点已经被遍历过后,仍然会对其入度进行修改,使得入度变为-1,从而影响后续的拓扑排序。 解决方案: 将代码改回原始版本,即if(--d[j] == 0) q[++tt] = j;。 代码示例: 正确的代码如下所示: bool topsort(){ int hh = 0, tt = -1; for(int i=1; i<=n; i++){ if(!d[i]) q[++tt] = i; } while(hh <= tt){ int t = q[hh++]; for(int i=h[t]; i!=-1; i=ne[i]){ int j = e[i]; if(--d[j] == 0) q[++tt] = j; } } return tt == n-1; } 参考资料: 《算法竞赛进阶指南》

      评论
    • CSDN-Ada助手 CSDN-AI 官方账号 2024-04-21 18:38
      关注

      【相关推荐】



      • 这篇文章:【刷题算法】广度优先遍历BFS的最短路算法 也许有你想要的答案,你可以看看
      • 您还可以看一下 贺利坚老师的数据结构基础系列(7):图课程中的 BFS(广度优先搜索)的应用小节, 巩固相关知识点
      • 除此之外, 这篇博客: 算法基础系列第三章——层层推进的BFS中的 记录数据🎯 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
        
        typedef pair PII;
        PII prev_num[N][N];
        // 记录数据的伪代码如下:
        prev_num[x][y] = 探索前的坐标
        
        //记录上个状态的位置
        prev_num[a][b] = t;
        
        1. 涉及的stl容器:pair(数对)是将2个数据组合成一组数据。pair的实现是一个结构体,主要的两个成员变量first和second,分别存储两个数据。因为我们要输出的是一组坐标,那么用数对pair来记录会让我们,如鱼得水你讲

        2. 关于prev_num[x][y] = 探索前的点,有小伙伴读起来可能比较蒙,what’s this ?!各位看官,可这种理解喔💓💓💓。
          现在有一个二维矩阵,矩阵的类型是存放一组int型变量的数对,矩阵的名字是prev_num。现在让矩阵中位置是(x,y)的这块空间存放探索前的坐标t(这个坐标肯定也是数对类型的啦~)


      如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
      评论
    编辑
    预览

    报告相同问题?

  • 相关阅读:
    lio-sam框架:点云匹配之手写高斯牛顿下降优化求状态量更新
    【C++】递归,搜索与回溯算法入门介绍和专题一讲解
    java制作游戏,如何使用libgdx,入门级别教学
    上交所实时行情文件汇总
    软件工程:帕金森定律,项目工期的那点事儿
    springboot(ssm大学生成绩管理系统 成绩管理平台Java(code&LW)
    ubuntu 设置x11vnc服务
    阿里巴巴面试题- - -Java体系最新面试题(5)
    使用Java构建RESTful API:实现灵活、可扩展的Web服务
    Springboot+基于微信小程序的商城 毕业设计-附源码191145
  • 原文地址:https://ask.csdn.net/questions/8092300