Floyd - Greg and Graph - CodeForces 295B

Floyd - Greg and Graph - CodeForces 295B

题意:

给 定 一 个 n 个 点 的 有 向 完 全 图 , 给定一个n个点的有向完全图, n

现 在 依 次 删 除 n 个 点 , 现在依次删除n个点, n

删 除 每 个 点 之 前 , 输 出 当 前 图 中 任 意 两 点 之 间 的 最 短 距 离 之 和 。 删除每个点之前,输出当前图中任意两点之间的最短距离之和。

输入:

首 行 一 个 正 整 数 n , 表 示 点 的 个 数 。 首行一个正整数n,表示点的个数。 n

接 着 输 入 一 个 n × n 的 邻 接 矩 阵 w 。 接着输入一个n×n的邻接矩阵w。 n×nw

最 后 一 行 输 入 n 个 数 , 表 示 依 次 删 除 这 n 个 点 。 最后一行输入n个数,表示依次删除这n个点。 nn

输出:

n 个 数 , 表 示 依 次 删 除 n 个 点 之 前 , 任 意 两 点 之 间 的 最 短 距 离 之 和 。 n个数,表示依次删除n个点之前,任意两点之间的最短距离之和。 nn

Examples
Input

1
0
1

Output

0 

Input

2
0 5
4 0
1 2

Output

9 0 

Input

4
0 3 1 1
6 0 400 1
2 4 0 1
1 1 1 0
4 1 2 3

Output

17 23 404 0 

数据范围:

1   ≤   n   ≤   500 , 1   ≤   w i j   ≤   1 0 5 , w i i   =   0 1 ≤ n ≤ 500,1 ≤ w_ {ij} ≤ 10^5,w_{ii} = 0 1n5001wij105,wii=0


分析:

要 求 任 意 两 点 之 间 的 距 离 , 考 虑 F l o y d 算 法 。 要求任意两点之间的距离,考虑Floyd算法。 Floyd

最 暴 力 的 想 法 : 每 次 删 除 一 个 点 就 更 新 一 次 图 , 再 对 新 图 跑 一 遍 F l o y d , 时 间 复 杂 度 为 O ( n 4 ) 。 最暴力的想法:每次删除一个点就更新一次图,再对新图跑一遍Floyd,时间复杂度为O(n^4)。 FloydO(n4)

考 虑 F l o y d 算 法 最 外 层 k 的 含 义 , 表 示 考 虑 了 前 k 个 点 的 最 短 路 , 考虑Floyd算法最外层k的含义,表示考虑了前k个点的最短路, Floydkk

当 循 环 过 第 k 层 时 , 前 k 个 点 , 任 意 两 点 之 间 的 距 离 就 是 最 短 距 离 。 当循环过第k层时,前k个点,任意两点之间的距离就是最短距离。 kk

因 此 , 我 们 将 依 次 删 除 n 个 点 反 过 来 看 作 依 次 添 加 n 个 点 , 倒 序 读 入 删 除 点 的 顺 序 即 添 加 点 的 顺 序 。 因此,我们将依次删除n个点反过来看作依次添加n个点,倒序读入删除点的顺序即添加点的顺序。 nn

根 据 添 加 点 的 顺 序 来 跑 F l o y d 算 法 。 根据添加点的顺序来跑Floyd算法。 Floyd

只 要 按 照 添 加 的 顺 序 来 累 加 即 可 。 只要按照添加的顺序来累加即可。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>

#define ll long long

using namespace std;

const int N=510;

int n;
ll g[N][N];
int ver[N];
ll ans[N];

void floyd()
{
    for(int u=1;u<=n;u++)
    {
        int k=ver[u];
        for(int v=1;v<=n;v++)
            for(int w=1;w<=n;w++)
            {
                int i=ver[v], j=ver[w];
                g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
                if(v<=u&&w<=u) ans[u]+=g[i][j];     //点的顺序
            }
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin>>g[i][j];
    for(int i=n;i;i--) scanf("%d",&ver[i]);
    
    floyd();
    
    for(int i=n;i;i--) cout<<ans[i]<<' ';
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值