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

    你可能感兴趣的文章
    Node.js官网无法正常访问时安装NodeJS的方法
    查看>>
    Node.js的循环与异步问题
    查看>>
    Node.js高级编程:用Javascript构建可伸缩应用(1)1.1 介绍和安装-安装Node
    查看>>
    nodejs + socket.io 同时使用http 和 https
    查看>>
    NodeJS @kubernetes/client-node连接到kubernetes集群的方法
    查看>>
    Nodejs express 获取url参数,post参数的三种方式
    查看>>
    nodejs http小爬虫
    查看>>
    nodejs libararies
    查看>>
    nodejs npm常用命令
    查看>>
    Nodejs process.nextTick() 使用详解
    查看>>
    nodejs 创建HTTP服务器详解
    查看>>
    nodejs 发起 GET 请求示例和 POST 请求示例
    查看>>
    NodeJS 导入导出模块的方法( 代码演示 )
    查看>>
    nodejs 开发websocket 笔记
    查看>>
    nodejs 的 Buffer 详解
    查看>>
    nodejs 读取xlsx文件内容
    查看>>
    nodejs 运行CMD命令
    查看>>
    Nodejs+Express+Mysql实现简单用户管理增删改查
    查看>>
    nodejs+nginx获取真实ip
    查看>>
    nodejs-mime类型
    查看>>