Interview Questions: Directed Graphs

本文探讨了如何在有向图中寻找具有最少边的有向环,以及如何确定有向无环图(DAG)是否存在哈密顿路径。给出了从每个顶点运行BFS查找最短有向环的提示,以及通过拓扑排序寻找哈密顿路径的方法。同时,提出了线性时间算法来检查DAG和一般有向图中是否存在一个顶点可以从其他所有顶点到达,并给出相应的解决方案。

Directed Graphs

Shortest directed cycle. Given a digraph G, design an efficient algorithm to find a directed cycle with the minimum number of edges (or report that the graph is acyclic). The running time of your algorithm should be at most proportional to V(E+V) and use space proportional to E+V, where V is the number of vertices and E is the number of edges.

Hint: run BFS from each vertex.

参考 ShortestDirectedCycle.java

Hamiltonian path in a DAG. Given a directed acyclic graph, design a linear-time algorithm to determine whether it has a Hamiltonian path (a simple path that visits every vertex), and if so, find one.

Hint: topological sort.

先计算出该图的拓扑排序序列,再判断该序列中任意两个连续的结点是否相连,若是则存在哈密顿回路,且结点顺序正是拓扑序列,若不是则不存在哈密顿回路。

import edu.princeton.cs.algs4.Digraph;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Hamiltonian {
    private List<Integer> path;
    private boolean marked[];
    private boolean hasPath;
    private Digraph G;

    public Hamiltonian(Digraph G) {
        path = new ArrayList<>();
        marked = new boolean[G.V()];
        hasPath = true;
        this.G = G;

        for (int v = 0; v < G.V(); v++) {
            if (!marked[v]) {
                dfs(v);
            }
        }
        Collections.reverse(path);

        for (int i = 0; i < path.size() - 1; i++) {
            int v = path.get(i);
            int w = path.get(i + 1);
            boolean found = false;
            for (int u : G.adj(v)) {
                if (u == w) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                hasPath = false;
                break;
            }
        }
    }

    public boolean hasPath() {
        return hasPath;
    }

    public Iterable<Integer> getPath() {
        return path;
    }

    private void dfs(int v) {
        marked[v] = true;
        for (int w : G.adj(v)) {
            if (!marked[w]) {
                dfs(w);
            }
        }
        path.add(v);
    }
}

Reachable vertex.

  • DAG: Design a linear-time algorithm to determine whether a DAG has a vertex that is reachable from every other vertex, and if so, find one.
  • Digraph: Design a linear-time algorithm to determine whether a digraph has a vertex that is reachable from every other vertex, and if so, find one.

Hint (DAG): compute the outdegree of each vertex.

Hint (digraph): compute the strong components and look at the kernel DAG (the digraph that results when you contract each strong component to a single vertex).

DAG:对于有向无环图来说,如果存在一个点X,图中其他所有点都有路径到达X,那么X的出度必为0。如果不为0,假设X能够到达点Y,而Y又有路径到达X,就构成了环,与DAG的前提矛盾。找到出度为0的点后(可能多个),在图 G G G的逆向图 G R G^R GR中判断能否从X到达所有的点(一次DFS即可),如果能说明X就是要找的点。

Digraph:对于更普遍情况的有向图,先利用Kosaraju方法标识出所有强连通分量,id最小的强连通分量中的所有点就是候选点。针对每个候选点X,在图 G G G的逆向图 G R G^R GR中判断能否从X到达所有的点(一次DFS即可),如果能说明X就是要找的点。

在这里插入图片描述

使用C++实现有向的邻接矩阵,以及可达矩阵的计算算法。 请完成Project05.cpp中DirectedGraph类的成员函数,具体要求如下: DirectedGraph类: 用来表示一个有向。 成员变量: m_AdjMat:邻接矩阵 m_ReachabilityMat:可达矩阵 成员函数: DirectedGraph():默认构造函数,构造一个空。 ~DirectedGraph():析构函数 DirectedGraph(string filepath):解析文件filepath,构造一个DirectedGraph对象。 filepath文件格式与项目四相同,但本项目的为有向DirectedGraph(const Graph & graph):复制构造函数 operator=(const Graph & graph):赋值运算符 ClearGraph():清空的邻接矩阵和可达矩阵。 OutputGraph():输出的邻接矩阵 operator*(const DirectedGraph & graph): 乘法运算符,用于实现可达矩阵运算中的矩阵逻辑乘 DirectedGraph Pow(int power):邻接矩阵的整数次幂。 用法如下: DirectedGraph a; a = a.Pow(5); 即a的5次幂,相当于a = a * a * a * a * a; 注意要考虑0次幂的情况。 该函数适合以递归实现。 DirectedGraph MatOr(DirectedGraph graph):矩阵逐元素的逻辑或运算。 例如: 1 0 0 1 与 0 1 1 0 运算后的结果为 1 1 1 1 void CalcReachabilityMat():计算可达矩阵,要求该函数基于*运算符和Pow函数实现 void OutputReachabilityMat():输出可达矩阵 IsConnected(int src, int dst):基于可达矩阵判断从节点src与dst之间是否存在通路,如存在返回真,否则返回假
05-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值