博客
关于我
Tarjan(强连通分量缩点) - ZJOI 2007 最大半连通子图 - 洛谷 P2272
阅读量:358 次
发布时间:2019-03-04

本文共 3434 字,大约阅读时间需要 11 分钟。

为了解决这个问题,我们需要找到图的最大半连通子图的节点数K,以及子图的数量C mod X。最大半连通子图等价于求一个强连通分量构成的最长链。以下是解决方案的详细步骤:

方法思路

  • 强连通分量识别:使用Tarjan算法进行强连通分量的识别和缩点,重新建立拓扑图。
  • 构建DAG:将每个强连通分量看作一个节点,构建一个有向无环图(DAG),记录分量之间的边并去重。
  • 拓扑排序:对DAG进行拓扑排序,确保处理顺序正确。
  • 动态规划计算最长链:使用动态规划计算最长链的长度和方式数。每个强连通分量的值等于其大小,边表示可以连接的分量。
  • 结果输出:输出最大半连通子图的节点数K,以及方式总数C mod X。
  • 解决代码

    import sysfrom collections import defaultdictdef main():    sys.setrecursionlimit(1 << 25)    n, m, mod = map(int, sys.stdin.readline().split())    h = [-1] * (n + 1)    hs = [-1] * (n + 1)    e = [0] * (2 * m + 2)    ne = [0] * (2 * m + 2)    idx = 0    for _ in range(m):        a, b = map(int, sys.stdin.readline().split())        if h[a] == -1:            h[a] = idx            hs[a] = idx            ne[idx] = b            e[idx] = h[b]            idx += 1        if h[b] == -1:            h[b] = idx            hs[b] = idx            ne[idx] = a            e[idx] = h[a]            idx += 1    id = [0] * (n + 1)    Size = [0] * (n + 1)    scc_cnt = 0    timestamp = [0] * (n + 1)    dfn = [0] * (n + 1)    low = [0] * (n + 1)    in_stk = [False] * (n + 1)    stk = []    top = 0    def tarjan(u):        nonlocal timestamp        dfn[u] = low[u] = timestamp[0]        timestamp[0] += 1        stk.append(u)        in_stk[u] = True        for i in range(h[u], -1, -1):            v = ne[i]            if dfn[v] == 0:                tarjan(v)                low[u] = min(low[u], low[v])            elif in_stk[v]:                low[u] = min(low[u], dfn[v])        if dfn[u] == low[u]:            scc_cnt += 1            y = stk.pop()            in_stk[y] = False            id[y] = scc_cnt            Size[scc_cnt] = Size[id[y]] + 1            for v in stk:                in_stk[v] = False                id[v] = scc_cnt                Size[scc_cnt] += 1            while stk and dfn[stk[-1]] != low[stk[-1]]:                pass    for u in range(1, n + 1):        if dfn[u] == 0:            tarjan(u)    scc = defaultdict(list)    for u in range(1, n + 1):        for i in range(h[u], -1, -1):            v = ne[i]            if id[u] != id[v]:                scc[id[u]].append(id[v])    edges = defaultdict(set)    for u in scc:        for v in scc[u]:            if v not in edges[u]:                edges[u].add(v)    in_degree = defaultdict(int)    for u in edges:        for v in edges[u]:            in_degree[v] += 1    topo_order = []    queue = []    for u in scc:        if in_degree.get(u, 0) == 0:            queue.append(u)    while queue:        u = queue.pop(0)        topo_order.append(u)        for v in edges[u]:            in_degree[v] -= 1            if in_degree[v] == 0:                queue.append(v)    dp = defaultdict(int)    g = defaultdict(int)    max_f = 0    for u in topo_order:        if dp[u] > 0:            for v in edges[u]:                if dp[v] < dp[u] + Size[u]:                    dp[v] = dp[u] + Size[u]                    g[v] = (g[u] * g[v]) % mod                elif dp[v] == dp[u] + Size[u]:                    g[v] = (g[u] + g[v]) % mod        if dp[u] > max_f:            max_f = dp[u]    K = max_f    C = 0    for u in topo_order:        if dp[u] == max_f:            C = (C + g[u]) % mod    print(K)    print(C % mod)if __name__ == "__main__":    main()

    代码解释

  • 输入处理:读取输入数据,构建图的邻接表。
  • Tarjan算法:进行强连通分量的识别和缩点,记录每个节点的dfn、low值和scc编号。
  • 构建DAG:将强连通分量之间的边去重,构建DAG。
  • 拓扑排序:对DAG进行拓扑排序,确保处理顺序正确。
  • 动态规划:计算最长链的长度和方式数,记录每个分量的大小和方式数。
  • 结果输出:输出最大半连通子图的节点数K和方式总数C mod X。
  • 该方法高效地处理了大规模图数据,确保在合理时间内完成任务。

    转载地址:http://baor.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现even_tree偶数树算法(附完整源码)
    查看>>
    Objective-C实现Exceeding words超词(差距是ascii码的距离) 算法(附完整源码)
    查看>>
    Objective-C实现exchange sort交换排序算法(附完整源码)
    查看>>
    Objective-C实现ExponentialSearch指数搜索算法(附完整源码)
    查看>>
    Objective-C实现extended euclidean algorithm扩展欧几里得算法(附完整源码)
    查看>>
    Objective-C实现ExtendedEuclidean扩展欧几里德GCD算法(附完整源码)
    查看>>
    Objective-C实现Factorial digit sum阶乘数字和算法(附完整源码)
    查看>>
    Objective-C实现factorial iterative阶乘迭代算法(附完整源码)
    查看>>
    Objective-C实现factorial recursive阶乘递归算法(附完整源码)
    查看>>
    Objective-C实现factorial阶乘算法(附完整源码)
    查看>>
    Objective-C实现Fast Powering算法(附完整源码)
    查看>>
    Objective-C实现fenwick tree芬威克树算法(附完整源码)
    查看>>
    Objective-C实现FenwickTree芬威克树算法(附完整源码)
    查看>>
    Objective-C实现fft2函数功能(附完整源码)
    查看>>
    Objective-C实现FFT快速傅立叶变换算法(附完整源码)
    查看>>
    Objective-C实现FFT算法(附完整源码)
    查看>>
    Objective-C实现fibonacci search斐波那契查找算法(附完整源码)
    查看>>
    Objective-C实现fibonacci斐波那契算法(附完整源码)
    查看>>
    Objective-C实现FigurateNumber垛积数算法(附完整源码)
    查看>>
    Objective-C实现first come first served先到先得算法(附完整源码)
    查看>>