博客
关于我
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/

    你可能感兴趣的文章
    Neo4j(2):环境搭建
    查看>>
    nessus快速安装使用指南(非常详细)零基础入门到精通,收藏这一篇就够了
    查看>>
    Nessus漏洞扫描教程之配置Nessus
    查看>>
    Nest.js 6.0.0 正式版发布,基于 TypeScript 的 Node.js 框架
    查看>>
    Netpas:不一样的SD-WAN+ 保障网络通讯品质
    查看>>
    netsh advfirewall
    查看>>
    Netty WebSocket客户端
    查看>>
    Netty 异步任务调度与异步线程池
    查看>>
    Netty中集成Protobuf实现Java对象数据传递
    查看>>
    Netty工作笔记0006---NIO的Buffer说明
    查看>>
    Netty工作笔记0011---Channel应用案例2
    查看>>
    Netty工作笔记0013---Channel应用案例4Copy图片
    查看>>
    Netty工作笔记0014---Buffer类型化和只读
    查看>>
    Netty工作笔记0020---Selectionkey在NIO体系
    查看>>
    Vue踩坑笔记 - 关于vue静态资源引入的问题
    查看>>
    Netty工作笔记0025---SocketChannel API
    查看>>
    Netty工作笔记0027---NIO 网络编程应用--群聊系统2--服务器编写2
    查看>>
    Netty工作笔记0050---Netty核心模块1
    查看>>
    Netty工作笔记0060---Tcp长连接和短连接_Http长连接和短连接_UDP长连接和短连接
    查看>>
    Netty工作笔记0077---handler链调用机制实例4
    查看>>