Codeforces 295B 《Greg and Graph》

原创建时间:2018-09-30 20:21:16

开倒车 倒序 Floyd

题目链接

题目描述

翻译来自洛谷

Greg有一个有边权的有向图,包含 (n) 个点。这个图的每两个点之间都有两个方向的边。Greg喜欢用他的图玩游戏,现在他发明了一种新游戏:

  • 游戏包含 (n) 步。
  • (i) 步Greg从图中删掉编号为 (x_i) 的点。当删除一个点时,这个点的出边和入边都会被删除。
  • 在执行每一步之前,Greg想知道所有点对间最短路长度的和。最短路可以经过任何没删掉的点。换句话说,如果我们假设 (d(i, v, u)) 是在删掉 (x_i)(v)(u) 间的最短路长度,那么Greg想知道下面这个求和的值:$$sum_{v, u, v eq u} d(i, v, u)$$

帮帮Greg,输出每一步之前要求的值。

Input / Output 格式 & 样例

输入格式

第一行包含一个整数 (n (1 leq n leq 500)) ,代表图中的点数。

下面 (n) 行每行包含 (n) 个整数,代表边权:第 (i) 行的第 (j) 个数 (a_{ij} (1 leq a_{ij} leq 10^5, a_{ii} = 0)) 代表从 (i)(j) 的边权。

最后一行包含 (n) 个整数: (x_1, x_2, dots, x_n (1 leq x_i leq n)) ,分别为Greg每一步删掉的点的编号。

输出格式

输出 (n) 个整数,第 (i) 个数等于游戏的第 (i) 步之前统计的求和值。

请不要在C++中使用%lld标志来输出64位整数long long,推荐使用cin, cout流或者用%I64d标志。

输入样例

Case #1:

1
0
1

Case #2:

2
0 5
4 0
1 2

Case #3:

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

输出格式

Case #1:

0

Case #2:

9 0

Case #3:

17 23 404 0

解析

(n le 500)

很明显跑 Floyd 了

但是 Floyd 不支持删除操作

怎么办?

开倒车 倒序添加!

我们记录下删除点的信息,再倒着添加回去,在这个过程中套一个 Floyd 进去

要注意的是累计答案的时候判断点是否存在

代码实现

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;

const int MAXN = 500 + 10;

int f[MAXN][MAXN];
int seq[MAXN];
long long int ans[MAXN];

bool inGraph[MAXN];

int n;

inline int getint() {
    int s = 0, x = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') x = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        s = s * 10 + ch - '0';
        ch = getchar();
    }
    return s * x;
}

inline void putint(int x, bool returnValue) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x >= 10) putint(x / 10, false);
    putchar(x % 10 + '0');
    if (returnValue) putchar('
');
}

inline void addEdge(int s, int t, int w) {
    f[s][t] = f[t][s] = w;
}

int main(int argc, char *const argv[]) {
    n = getint();
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            f[i][j] = getint();
        }
    }
    for (int i = 1; i <= n; ++i) {
        seq[i] = getint();
    }
    for (int l = n; l > 0; --l) {
        int k = seq[l];
        inGraph[k] = true;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                f[i][j] = std::min(f[i][j], f[i][k] + f[k][j]);
                if (inGraph[i] && inGraph[j]) ans[l] += f[i][j];
            }
        }
    }
    for (int i = 1; i <= n; ++i) cout << ans[i] << ' ';
    return 0;
}




原文地址:https://www.cnblogs.com/handwer/p/11745396.html