Codeforces 295 B Greg and Graph (Floyd_Warshall的深入理解)

来源:互联网 发布:淘宝怎么弄全球购图标 编辑:程序博客网 时间:2024/05/22 17:40

@(K ACMer)By题解工厂

      • 题意
      • 分析
      • Code


题意:

给你一个有向图,图中任意两点间皆有两个方向的两条边.并给定一个序列,按照序列顺序删除图中的顶点,问每次删除一个顶点之前图中所有两点间的最短距离为多少.


分析:

想到任意两点间的最短距离首先想到的就是Floyd_Warshall算法.要做这个题需要深入理解该算法的思想.
先看原始的算法实现:

void floydwarshall(void){    for (int k = 1; k <= v; k++)        for (int i = 1; i <= v; i++)            for (int j = 1; j <= v; j++)                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);}
  • 最外层的k循环代表的是,一个节点集合,k每加一就向集合中多加入一个顶点,而且是按照节点编号大小增序加入的.一个顶点都没有集合为:,然后k加一集合变为1,然后{1,2}, {1,2,3},…..{1,2,3,...v}直到所有节点加入集合.(*注意:这些集合中的节点表示的是路径可以经过的节点,而不包括两端的.两端的节点一定可以用.)
  • 每加入一个节点该算法就更新一次所有两点间的最短距离.

结合这个题,他按照序列顺序删除节点,那么我们就可以反过来,按照序列逆序,往集合中加入节点就可以达到目标效果了.


Code:

#include <bits/stdc++.h>using namespace std;typedef long long LL;int dp[1000][1000], v;vector<LL> G, ans, temp;void floydwarshall(void){    for (int vi = G.size() - 1; vi >= 0; vi--) {        LL k = G[vi], an = 0;        temp.push_back(k);        for (int i = 1; i <= v; i++)            for (int j = 1; j <= v; j++)                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);        for (int i = 0; i < temp.size(); i++) {            for (int j = 0; j < temp.size(); j++)                an += dp[temp[i]][temp[j]];        }        ans.push_back(an);    }}int main(void){    while (cin >> v) {        for (int i = 1; i <= v; i++)            for (int j = 1; j <= v; j++)                cin >> dp[i][j];        for (int i = 0; i < v; i++) {            int x;            cin >> x;            G.push_back(x);        }        floydwarshall();        for (int i = ans.size() - 1; i >= 0; i--)            cout << ans[i] << " ";    }    return 0;}
0 0
原创粉丝点击