最短距离总和
题目详情
给定一张带权无向完全图,设点的编号为 1,2,3,4,5....n(以邻接矩阵的形式给出)。
计算依次拿走第 i 个点后,剩余所有点到其他点的最短距离之和的总和(具体请看样例)。
输入格式
第一行包含一个整数n。
接下来 n 行,每行包含 n 个空格隔开的整数,表示邻接矩阵,其中第 i 行第 j 列的数字 表示点 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;
}