📜  门| GATE CS 2020 |问题 15(1)

📅  最后修改于: 2023-12-03 14:58:21.086000             🧑  作者: Mango

门 | GATE CS 2020 | 问题 15

题目描述

本问题是关于图论的问题。给定一个无向加权图G = (V, E),其中V是节点的集合,E是边集合,每条边 (u, v) 的权重为 w(u, v)。在该图中,给定源节点s和目标节点t。我们需要找到从s到t的一条简单路径,使得路径上所有边的权重和最大。让该权重和为P。现在添加一些额外的边 (u, v),这将使得图形成一个环。我们需要添加的边 (u, v) 的权重为X。此时,找到从s到t的一条简单路径,使得路径上所有边的权重和最大,并返回路径的权重和。

输入格式

输入的第一行包含两个整数 n 和 m ,分别表示节点数和边数。

接下来的m行包含三个整数u, v和w,表示无向加权边 (u, v) 的两个节点和它们之间的权重w。

接下来一行包含两个整数s和t,表示需要找到的源节点和目标节点。

接下来一行包含一个整数 q ,表示需要添加的边数。

接下来q行,每行包含三个整数u, v和X,表示需要添加一条从u到v的边,其权重为X。

图保证无重边和自环,而且原始图保证从s到t至少存在一条路径。

输出格式

输出一个整数,表示找到从s到t的一条简单路径,使得路径上所有边的权重和最大,并返回路径的权重和。

示例

输入:

3 3
1 2 3
2 3 4
3 1 5
1 2
1

输出:

9
解题思路

本题是一道图论的问题。通过给定的源节点和目的节点,需要找到连接这两个节点的一条最大权重的路径。当一个节点连通到自己或者存在环时,我们可以想到利用Floyd华沙尔算法求解最短(长)路径。最长路径长度是所有最短路径长度取负得到的。但是,本题新增了一些边,这些新增的边会形成一个环,我们需要对此进行分析。

我们先在原图中找出从s到t的最长路径P。如果新添加的边没有连接P上的任何节点,那么它不会对答案造成任何影响。否则,它将形成一个环,我们需要找到路径P上的边(L, R),连接它们的这个边(u, v),并将其权重设置为X。然后,我们可以通过将P分解为从s到L的路径1,从L到R的路径2,和从R到t的路径3。设路径2包含k个节点,那么从源节点到目标节点的最长路径的长度是max(P,P1 + X + k*P2 + X + P3)。

我们需要预处理出P1,P2和P3。接下来只要遍历所有新添加的边(u, v),计算以上式子的值即可。

参考代码
def get_longest_path(n, m, edges, s, t):
    # 初始图和图的反向的权重
    graph = [[] for i in range(n)]
    graph_r = [[] for i in range(n)]
    for u, v, w in edges:
        graph[u - 1].append((v - 1, w))
        graph_r[v - 1].append((u - 1, w))

    # 分别计算从 s 到 t 和从 t 到 s 的最长路径
    dist_s = [float('-infinity')] * n
    pq_s = [(0, s - 1)]
    dist_s[s - 1] = 0
    while pq_s:
        dist, u = heapq.heappop(pq_s)
        if dist_s[u] != dist:
            continue
        for v, w in graph[u]:
            if dist_s[v] < dist + w:
                dist_s[v] = dist + w
                heapq.heappush(pq_s, (dist_s[v], v))

    dist_t = [float('-infinity')] * n
    pq_t = [(0, t - 1)]
    dist_t[t - 1] = 0
    while pq_t:
        dist, u = heapq.heappop(pq_t)
        if dist_t[u] != dist:
            continue
        for v, w in graph_r[u]:
            if dist_t[v] < dist + w:
                dist_t[v] = dist + w
                heapq.heappush(pq_t, (dist_t[v], v))

    # 计算从 s 到 t 最长路径上的所有边的权重和
    ans = dist_s[t - 1]
    for u, v, w in edges:
        ans = max(ans, dist_s[u - 1] + w + dist_t[v - 1])

    return ans

def solve(n, m, edges, s, t, q, new_edges):
    # 计算原图中从 s 到 t 的最长路径
    P = get_longest_path(n, m, edges, s, t)

    # 计算从 s 到 t 最长路径上的所有边的权重和
    P1, P2, P3 = 0, 0, 0
    L, R = None, None
    for i in range(len(new_edges)):
        u, v, w = new_edges[i]
        if P1 == 0 and (u == s or v == s):
            P1 = get_longest_path(n, m, edges, s, u if v == s else v)
        if P3 == 0 and (u == t or v == t):
            P3 = get_longest_path(n, m, edges, u if v == t else v, t)
        if u == s and v == t:
            ans = max(P, P1 + w + P3)
            return ans
        elif u == s or u == t:
            x, y = u, v
        elif v == s or v == t:
            x, y = v, u
        else:
            continue
        if P2 < get_longest_path(n, m, edges, x, y):
            P2 = get_longest_path(n, m, edges, x, y)
            L, R = x, y

    # 组合计算 s 到 t 的最长路径
    ans = P
    if L is not None and R is not None:
        ans = max(ans, P1 + new_edges[-1][2] + P2 + new_edges[-1][2] + P3)

    return ans

n, m = 3, 3
edges = [(1, 2, 3), (2, 3, 4), (3, 1, 5)]
s, t = 1, 2
q = 1
new_edges = [(3, 2, 1)]

ans = solve(n, m, edges, s, t, q, new_edges)

print(ans)

注:以上是python实现的参考代码,需要用到堆(heapq)的数据结构辅助计算,可以自行百度了解。