📜  门| GATE CS 2019 |第 48 题(1)

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

门- GATE CS 2019- 第48题

本题考查图论的知识。给定一张带权无向图,每一条边的权值均为正整数。定义图中的路径为一系列不同的顶点,路径上相邻的顶点通过一条边相连。定义一条路径的权值为该路径上所有边的权值之和。现在需要找到一条从起点到终点的最优路径,使得该路径与所有其他最短路径的路径权值之和的平方之和最小。

下面介绍算法实现细节:

输入格式

输入包括多个测试样例。对于每个测试样例,第一行包括一个整数N(2<=N<=20),表示顶点个数。接下来N行,每行包括N个整数,表示图的邻接矩阵,对角线上的元素值为0,其它元素表示相应两个顶点间的边权值(保证不超过100)。最后两个整数S和T(0<=S,T<N,S!=T)分别表示起点和终点。

示例输入:

3
0 2 3
2 0 3 
3 3 0
0 2
3 1
2
1 2 3
4 5 6
7 8 9
0 2
2 1
输出格式

对于每个测试样例,输出一个整数,表示该最优路径与所有其他最短路径的路径权值之和的平方之和的最小值。

示例输出:

2
285
解题思路

需要用到最短路的思想,可以结合Floyd算法在动态规划过程中求出矩阵M,其中M[i][j]表示从i到j的最短路径长度。然后先对i、j的值进行排序,再设dp[i][k]表示起点到i的最短距离为k时,经过i到终点的最短距离。此时有dp[i][0]等于M[i][t]。状态转移方程为:

dp[i][k] = M[i][t] + ∑ min (dp[j][k-1], M[j][t])^2 (j != i && j <= i)

其中∑是对j<=i的顶点求和。当k=1时,dp[i][1]即为M[i][t]。最后输出dp[s][k]的值即可。

代码实现

下面是Python代码的实现部分,其中adj矩阵是给出的带权图邻接矩阵:

#输入部分
from typing import List

n=int(input())
adj = []
for i in range(n):
    adj.append([])
    adj[i] += map(int, input().split())

s,t = map(int, input().split())

def minFrodo(n: int,adj: List[List[int]],s: int,t : int) -> int:
    # 初始化矩阵
    dp = []
    for i in range(n):
        dp.append([])

    for i in range(n):
        for j in range(n):
            dp[i].append(1000000)

    # 初始化dp数组
    for i in range(n):
        dp[i][0] = adj[i][t]

    # 动态规划的转移过程
    for k in range(1, n):
        for i in range(n):
            if i != s:
                for j in range(i):
                    if j != s:
                        dp[i][k] = min(dp[i][k], adj[i][j] + min(dp[j][k - 1], adj[j][t]))

        result = dp[s][1:t] + ((dp[t][1:s] + [0])[::-1])
        ans = dp[s][0] ** 2
        for i in range(t - s - 1 + 1):
            ans += (result[i] ** 2)

    return ans

print(minFrodo(n,adj,s,t))

在上述代码实现中,minFrodo是算法部分的主要函数,它的输入参数包括节点的个数n、带权邻接矩阵adj、起始点s、结束点t。其中s和t等于特定的节点编号,即从s到t要求的最短路径。算法逻辑过程中DP部分的实现细节在代码中有进一步释义。