Algorithm 补图算法中的最短路径

Algorithm 补图算法中的最短路径,algorithm,data-structures,big-o,graph-theory,breadth-first-search,Algorithm,Data Structures,Big O,Graph Theory,Breadth First Search,我今天参加了一个测试(数据结构课程),其中一个问题是: 给定一个无向非加权图G=(V,E),您需要编写一个算法,对于给定的节点s,返回从s到补码图中所有节点V'的最短路径 补码图G'=(E',V')包含G中不共享边且仅共享边的任何to节点之间的边 该算法需要在(原始图的)O(V+E)中运行 我问了50个不同的学生,他们中甚至没有一个正确地解决了这个问题 有什么想法吗? 谢谢, 巴拉克。课程工作人员已经公布了考试的正式答案 答案是: “该算法基于BFS,并进行了一些调整。 对于图中的每个节点,我们

我今天参加了一个测试(数据结构课程),其中一个问题是: 给定一个无向非加权图G=(V,E),您需要编写一个算法,对于给定的节点s,返回从s到补码图中所有节点V'的最短路径

补码图G'=(E',V')包含G中不共享边且仅共享边的任何to节点之间的边

该算法需要在(原始图的)O(V+E)中运行

我问了50个不同的学生,他们中甚至没有一个正确地解决了这个问题

有什么想法吗? 谢谢,
巴拉克。

课程工作人员已经公布了考试的正式答案

答案是:

“该算法基于BFS,并进行了一些调整。 对于图中的每个节点,我们将添加两个字段-next和prev。使用这两个字段,我们可以维护两个节点的双链接列表:L1、L2。 在算法的每次迭代开始时,L1在图中具有所有while节点,L2为空。 BFS代码(无初始化)为:

在第3-5行的循环结束处,L1包含G中与u不相邻的所有白色节点,或者换句话说,在补码图中与u相邻的所有白色节点。 因此,算法的运行时间等于补图上原始BFS的运行时间。 时间是O(V+E),因为第4-5行最多执行2E次,第7-9行最多执行V次(每个节点只能从L1中退出一次)。”

注意:这是从希伯来语翻译过来的原始解决方案

我希望你觉得这对我很有帮助,谢谢大家帮助我


巴拉克。

我想提出一种不同的方法

初始化:-

  • 创建未发现边的列表。让我们称之为
    未发现的
    ,并用所有节点初始化它
  • 然后,我们将运行BFS的修改版本
  • 创建一个队列(Q)并向其添加开始节点
  • 主算法

    未发现时。size()>0&&队列不为空

  • 当前节点
    =出列(队列)
  • 创建补码图中所有边的列表(我们称之为
    补边
    )。这可以通过循环所有 未发现
    中的节点并检查其是否连接到
    
    当前节点
  • 然后循环通过
    补足\u边中的每个节点
    执行3 操作

    • 如果最佳,则更新距离
    • 从未发现节点中删除此节点
    • 排队(队列,此节点)
  • 这里需要注意的一些事情, 如果初始图形是稀疏的,则
    未发现的
    将很快变为空。 在实现过程中,使用哈希将边存储在图形中,这将加快步骤2

    以下是示例代码:-

    HashSet<Integer> adjList[];           // graph stored as adjancency list
    
    public int[] calc_distance(int start){
            HashSet<Integer> undiscovered = new HashSet<>();
            for(int i=1;i<=N;i++){
                undiscovered.add(i);
            }
    
            int[] dist = new int[N+1];
            Arrays.fill(dist, Integer.MAX_VALUE/4);
    
    
            Queue<Integer> q = new LinkedList<>();
            q.add(start);
            dist[start] = 0;
    
            while(!q.isEmpty() && undiscovered.size()>0){
                int curr = q.poll();
    
                LinkedList<Integer> complement_edges = new LinkedList<>();
                for(int child : undiscovered){
                    if(!adjList[curr].contains(child)){
                        // curr and child is connected in complement
                        complement_edges.add(child);
                    }
                }
    
                for(int child : complement_edges){
                    if(dist[child]>(dist[curr]+1)){
                        dist[child] = dist[curr]+1;
                    }
                    // remove complement_edges from undiscovered
                    undiscovered.remove(child);
                    q.add(child);
                }
            }
    
            return dist;
        }
    }
    
    HashSet adjList[];//存储为邻接列表的图形
    公共整数[]计算距离(整数起点){
    HashSet unfounded=新HashSet();
    对于(int i=1;i0){
    int curr=q.poll();
    LinkedList补码_边=新LinkedList();
    for(int子项:未发现){
    如果(!adjList[curr].包含(子项)){
    //curr和child在补语中连接
    补充_边。添加(子项);
    }
    }
    for(整数子级:补边){
    如果(区[子]>(区[当前]+1)){
    dist[child]=dist[curr]+1;
    }
    //从未发现的边上删除补边
    未被发现。移除(儿童);
    q、 添加(儿童);
    }
    }
    返回距离;
    }
    }
    
    Hi,你可以肯定我在考试期间用了两个小时的大脑,之后又用了四个小时。这不是家庭作业,只是纯粹的好奇心。我同意Okuma的观点,你的问题更适合不同的堆栈交换站点。我推荐:你确定它应该是原始图的O(V+E)吗?你可以有一个非常稀疏的图,它会产生一个超密的补码,其中O(V'+E')会比O(V+E)大。是的,@miky,我敢肯定。对于O(V'+E'),它非常简单。我假设图是作为邻接列表给出的,否则你总是需要O(V^2),在这种情况下,证明O(V'+E')在O(V+E)中非常简单。如果图形以邻接列表的形式给出,那么证明O(V'+E')在O(V+E)中就有点困难了。@Miky Dinescu-正如你所要求的那样。非常感谢。谢谢你的回答,这对我帮助很大!