📜  门| GATE-CS-2007 |第 69 题(1)

📅  最后修改于: 2023-12-03 15:42:16.561000             🧑  作者: Mango

题目介绍

本题为2007年GATE计算机科学考试中的题目第69题。该题目涉及到算法和数据结构的知识,考查程序员对图论算法的掌握程度。

题目描述

给定一张无向连通图G,其中每个边的权值为正整数。设v是图G中任意一个结点,要求计算出v到G中其他结点之间的最短路径长度之和。

输入格式

第一行输入一个正整数n(2<=n<=1000),表示图G中的结点个数。

第二行输入一个正整数m(n-1<=m<=n*(n-1)/2),表示边的数量。

接下来的m行,每行包含三个正整数u,v和w,表示图G中存在一条从结点u到结点v的权值为w的无向边。

输出格式

输出一个正整数,表示v到G中其他结点之间的最短路径长度之和。

示例

输入:

3
3
1 2 1
2 3 2
1 3 3

输出:

5
解题思路

本题可以使用Dijkstra算法或者Floyd算法来实现。

Dijkstra算法:

使用一个数组dist[1...n]表示v到1...n号节点的最短路径长度。将所有的dist数组元素置为无穷大,将第v个元素置为0。

然后,将v加入到集合S中,使用while循环,不断地将集合S中的元素扩展到集合V-S中。如果V-S集合中的顶点i在dist中不为无穷大,那么v到i的最短路径还没确定。否则,v到i的最短路径为distv加上边(v,i)的权值,即disti=distv+w(v,i)。

继续循环,直到集合S中包含所有顶点。最终的dist数组就是v到图中所有顶点的最短距离。遍历一遍dist数组,就可以得到v到其他所有结点的最短路径长度之和。

Floyd算法:

Floyd算法是一种动态规划算法,用于计算任意两个结点之间的最短路径。它的时间复杂度为O(n^3)。

使用一个二维数组D[1...n][1...n]表示任意两个节点之间的最短路径长度。数组D的初始化需要根据图G中所有边的权值来进行。如果(u,v)表示图G中一条从u到v的边,那么D[u][v]=w(u,v),D[v][u]=w(u,v)。

假设现在要计算从v到其他结点的最短路径,那么只需要利用动态规划的思想,递推计算出所有的D[v][i]即可。递推的公式为:

D[v][i]=min{D[v][j]+D[j][i]},其中j是所有连接v和i的边的中间节点。

然后遍历一遍D[v]数组,即可得到v到其他结点之间的最短路径长度之和。

代码实现

这里给出使用Dijkstra算法的代码实现:

import heapq

def dijkstra(graph, v):
    n = len(graph)
    dist = [float('inf') for i in range(n)]
    dist[v] = 0
    hq = [(0, v)]

    while hq:
        cdist, node = heapq.heappop(hq)
        if dist[node] < cdist:
            continue

        for adj_node, w in graph[node]:
            if dist[node] + w < dist[adj_node]:
                dist[adj_node] = dist[node] + w
                heapq.heappush(hq, (dist[adj_node], adj_node))

    return dist

n = int(input().strip())
m = int(input().strip())

# 存储图中的边
edges = [[] for i in range(n)]
for i in range(m):
    u, v, w = map(int, input().strip().split())
    edges[u-1].append((v-1, w))
    edges[v-1].append((u-1, w))

v = 0  # 要求的结点
dist = dijkstra(edges, v)
ans = sum(dist)  # 计算路径长度之和
print(ans)

返回的markdown格式如下:

# 题目介绍

本题为2007年GATE计算机科学考试中的题目第69题。该题目涉及到算法和数据结构的知识,考查程序员对图论算法的掌握程度。

## 题目描述

给定一张无向连通图G,其中每个边的权值为正整数。设v是图G中任意一个结点,要求计算出v到G中其他结点之间的最短路径长度之和。 

## 输入格式

第一行输入一个正整数n(2<=n<=1000),表示图G中的结点个数。

第二行输入一个正整数m(n-1<=m<=n*(n-1)/2),表示边的数量。

接下来的m行,每行包含三个正整数u,v和w,表示图G中存在一条从结点u到结点v的权值为w的无向边。

## 输出格式

输出一个正整数,表示v到G中其他结点之间的最短路径长度之和。

## 示例

输入:

3 3 1 2 1 2 3 2 1 3 3

输出:

5


## 解题思路

本题可以使用Dijkstra算法或者Floyd算法来实现。

**Dijkstra算法:**

使用一个数组dist[1...n]表示v到1...n号节点的最短路径长度。将所有的dist数组元素置为无穷大,将第v个元素置为0。

然后,将v加入到集合S中,使用while循环,不断地将集合S中的元素扩展到集合V-S中。如果V-S集合中的顶点i在dist中不为无穷大,那么v到i的最短路径还没确定。否则,v到i的最短路径为distv加上边(v,i)的权值,即disti=distv+w(v,i)。

继续循环,直到集合S中包含所有顶点。最终的dist数组就是v到图中所有顶点的最短距离。遍历一遍dist数组,就可以得到v到其他所有结点的最短路径长度之和。

**Floyd算法:**

Floyd算法是一种动态规划算法,用于计算任意两个结点之间的最短路径。它的时间复杂度为O(n^3)。

使用一个二维数组D[1...n][1...n]表示任意两个节点之间的最短路径长度。数组D的初始化需要根据图G中所有边的权值来进行。如果(u,v)表示图G中一条从u到v的边,那么D[u][v]=w(u,v),D[v][u]=w(u,v)。

假设现在要计算从v到其他结点的最短路径,那么只需要利用动态规划的思想,递推计算出所有的D[v][i]即可。递推的公式为:

D[v][i]=min{D[v][j]+D[j][i]},其中j是所有连接v和i的边的中间节点。

然后遍历一遍D[v]数组,即可得到v到其他结点之间的最短路径长度之和。

## 代码实现

这里给出使用Dijkstra算法的代码实现:

```python
import heapq

def dijkstra(graph, v):
    n = len(graph)
    dist = [float('inf') for i in range(n)]
    dist[v] = 0
    hq = [(0, v)]

    while hq:
        cdist, node = heapq.heappop(hq)
        if dist[node] < cdist:
            continue

        for adj_node, w in graph[node]:
            if dist[node] + w < dist[adj_node]:
                dist[adj_node] = dist[node] + w
                heapq.heappush(hq, (dist[adj_node], adj_node))

    return dist

n = int(input().strip())
m = int(input().strip())

# 存储图中的边
edges = [[] for i in range(n)]
for i in range(m):
    u, v, w = map(int, input().strip().split())
    edges[u-1].append((v-1, w))
    edges[v-1].append((u-1, w))

v = 0  # 要求的结点
dist = dijkstra(edges, v)
ans = sum(dist)  # 计算路径长度之和
print(ans)