2017.1.18【初中部 】普及组模拟赛C组 小x的最短路 题解

来源:互联网 发布:淘宝网茵曼旗舰店 编辑:程序博客网 时间:2024/05/05 13:31

原题:

http://172.16.0.132/junior/#contest/show/1368/4

题目描述:

小x有一个由n个顶点构成的加权有向图,这张图中,任意两个顶点之间的都有两条方向不同的边。小x很喜欢玩图,现在他发明了一个新的游戏:
这个游戏共有n步。
在第i步时,小x把第xi个点从图中删除,同时删除所有与xi相连的边,包括xi的入边和出边。
每步操作进行前,小x想知道所有剩余顶点之间的最短路径的长度之和,最短路径可以通过任何剩余的顶点。换句话说,我们定义d(i,v,u)是在删除顶点xi之前,顶点v到顶点u的最短路径,小x想知道下面式子的值:

输入:

第一行包含一个整数n,表示图的顶点数。
接下来n行,每行n个整数,第i行第j个元素aij表示顶点i到顶点j的边的权值。
最后一行,包含n个不同的整数:x1,x2,…,xn(1<=xi<=n),表示小x删的顶点。

输出:

一行用1个空格分开的n个整数,第i个数表示在第i步前所求的值。行末没有多余的空格。

样例输入:

样例输入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

数据范围限制:

对于30%的数据:1<=n<=50
对于70%的数据:1<=n<=100
对于100%的数据:1<=n<=500,1<=xi<=n,1<=aij<=10^5,aii=0

实现:

#include <cstdio>#include <iostream>using std::min;int n, i, j, k, s[501], x[501], a[501][501];int main(){    freopen("shortest.in","r",stdin);freopen("shortest.out","w",stdout);    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", &x[i]);    for (k = n; k >= 1; k--)        for (i = 1; i <= n; i++)            for (j = 1; j <= n; j++)            {                a[x[i]][x[j]] = min(a[x[i]][x[j]], a[x[i]][x[k]] + a[x[k]][x[j]]);                if (i >= k && j >= k) s[k] += a[x[i]][x[j]];            }    for (i = 1; i <= n; i++) printf("%d ", s[i]);}
0 0