Greg and graph
题目描述
Greg has a weighed directed graph, consisting of n vertices. In this graph any pair of distinct vertices has an edge between them in both directions. Greg loves playing with the graph and now he has invented a new game:
- The game consists of n steps.
- On the i-th step Greg removes vertex number xi from the graph. As Greg removes a vertex, he also removes all the edges that go in and out of this vertex.
- Before executing each step, Greg wants to know the sum of lengths of the shortest paths between all pairs of the remaining vertices. The shortest path can go through any remaining vertex. In other words, if we assume that d(i, v, u)is the shortest path between vertices v and u in the graph that formed before deleting vertex xi, then Greg wants to know the value of the following sum: .
Help Greg, print the value of the required sum before each step.
题目大意:给定一个 n 个点 m 条边的无向图,再给定一个 1 ∼ n 的排列 P,现在要按排列中的次序一个个删掉图中的点,并求出每次删除后图中所有点之间最短路的和,不连通最短路算作 0。
输入格式
The first line contains integer n (1 ≤ n ≤ 500) — the number of vertices in the graph.
Next n lines contain n integers each — the graph adjacency matrix: the j-th number in the i-th line aij (1 ≤ aij ≤ 105, aii = 0) represents the weight of the edge that goes from vertex i to vertex j.
The next line contains n distinct integers: x1, x2, ..., xn (1 ≤ xi ≤ n) — the vertices that Greg deletes.
输出格式
Print n integers — the i-th number equals the required sum before the i-th step.
Please, do not use the %lld specifier to read or write 64-bit integers in C++. It is preferred to use the cin, cout streams of the %I64d specifier.
样例输入
#1
1
0
1
#2
2
0 5
4 0
1 2
#3
4
0 3 1 1
6 0 400 1
2 4 0 1
1 1 1 0
4 1 2 3
样例输出
#1
0
#2
9 0
#3
17 23 404 0
题解
本题时限3秒,n<=500,用Floyd。
如果每次删点后计算最短路,似乎只能n^3重新计算,还是很浪费时间的。。
不妨倒过来想,从空图中不断加点,类似Floyd往已算出任意两点最短路的点集中加点,可以降成n^2。
开始我边建图边求最短路,每次加入新点,在图中加上新点连的边,先求出新点到每个已加入的点的最短路,再更新每个已加入的点到新点的最短路。程序如下:
#include <cstdio> int n,q[505],g[505][505]; long long a[505][505],ans[505]; bool f[505]; int main() { int i,j,k; scanf("%d",&n); for (i=1;i<=n;i++) for (j=1;j<=n;j++) scanf("%d",&g[i][j]); for (i=1;i<=n;i++) scanf("%d",&q[i]); f[q[n]]=1; for (int ii=n-1;ii>=1;ii--) { k=q[ii]; f[k]=1; for (i=1;i<=n;i++) if (f[i]) a[k][i]=g[k][i], a[i][k]=g[i][k]; for (i=n;i>ii;i--) for (j=n;j>ii;j--) if (i!=j && a[k][q[i]]>a[k][q[j]]+a[q[j]][q[i]]) a[k][q[i]]=a[k][q[j]]+a[q[j]][q[i]]; for (i=n;i>=ii;i--) for (j=n;j>=ii;j--) if (i!=j && a[q[i]][q[j]]>a[q[i]][k]+a[k][q[j]]) a[q[i]][q[j]]=a[q[i]][k]+a[k][q[j]]; for (i=n;i>=ii;i--) for (j=n;j>=ii;j--) ans[ii]+=a[q[i]][q[j]]; } for (i=1;i<=n;i++) printf("%lld ",ans[i]); return 0; }
然而WA了。。。(╥╯^╰╥)
看半天不知道为什么o(╥﹏╥)o
好在最后还是懂了ヽ( ̄▽ ̄)ノ
当两点不连通时,最短路为0。而在建图过程中肯定会有两点不连通,加入新点后就连通的情况,但我把数组初始为0,那么起初不连通的两点即使后来连通了,根据Floyd的程序,最短路还是0。于是我就这样WA了。。。(。・_・。)
然后我改了程序,先把整个图建好,依旧以加点顺序求Floyd,最后求和时只加上都在图中的两点间的最短路。以下是AC代码:
#include <cstdio> int n,q[505],g[505][505]; long long a[505][505],ans[505]; bool f[505]; int main() { int i,j,k; scanf("%d",&n); for (i=1;i<=n;i++) for (j=1;j<=n;j++) scanf("%d",&a[i][j]); for (i=1;i<=n;i++) scanf("%d",&q[i]); for (int ii=n;ii>=1;ii--) { k=q[ii]; f[k]=1; for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (a[i][j]>a[i][k]+a[k][j]) a[i][j]=a[i][k]+a[k][j]; for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (f[i] && f[j]) ans[ii]+=a[i][j]; } for (i=1;i<=n;i++) printf("%lld ",ans[i]); return 0; }