3512. 最短距离总和

118 阅读2分钟

最短距离总和

题目详情

给定一张带权无向完全图,设点的编号为 1,2,3,4,5....n(以邻接矩阵的形式给出)。

计算依次拿走第 i 个点后,剩余所有点到其他点的最短距离之和的总和(具体请看样例)。

输入格式

第一行包含一个整数n。

接下来 n 行,每行包含 n 个空格隔开的整数,表示邻接矩阵,其中第 i 行第 j 列的数字 aija_{ij} 表示点 i 和点 j 之间存在一条边,长度为 aija_{ij}

输出格式

一个整数,表示最短距离之和的总和。

数据范围

1n5001≤n≤500,
ai=0a_i=0,
0<aij10 (ij)0<a_{ij}≤10 (i≠j)

样例解释

拿走 1 号点后,2,3,4 号点构成一个等边三角形,每个点到其他两点的最短距离都为 1,所以所有点到其他点的最短距离之和的总和为 2+2+2=6。

拿走 1,2号点后,3,4 号点之间存在一条边,边长为 1,所以所有点到其他点的最短距离之和的总和为 1+1=2。

拿走 1,2,3 号点后,仅剩 1 个点,不存在到其他点的最短距离。

拿走所有点后为空。

最终结果为6+2+0+0=8。

解题思路

这题思路很新奇,我们观察题目,每次都要在整个图的基础上去掉一个点,然后记录每个点到其他所有点的最短路并求和,再将所有点的最短路的和求和,得到答案。如果熟悉Floyd算法的话,我们会神奇地发现,其实这个过程就是Floyd算法的逆过程。所以我们先将图存进来,然后从后往前枚举点i用i来更新最短路,相当于依次添加一个点进来。然后再来两层循环,枚举每个点进行最短路更新,这里我们可以只枚举一半的点,因为是无向图,邻接矩阵是对称的 -> k=j+1。然后每次将符合条件的 最短路 * 2 求和即可得到最终答案。
核心代码如下

for(int i=n;i>=2;i--)
        for(int j=1;j<=n;j++)
            for(int k=j+1;k<=n;k++)
            {
                g[k][j] = g[j][k] = min(g[j][k],g[j][i]+g[i][k]);
                if(j >= i && k >= i)  res += g[j][k] *2;
            }

AC代码

#include<iostream>
using namespace std;

int g[505][505];

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>g[i][j];
        }
    }
    int res = 0;
    for(int i=n;i>=2;i--)
        for(int j=1;j<=n;j++)
            for(int k=j+1;k<=n;k++)
            {
                g[k][j] = g[j][k] = min(g[j][k],g[j][i]+g[i][k]);
                if(j >= i && k >= i)  res += g[j][k] *2;
            }
    cout<<res;
    
    return 0;
}