Greg and Graph
题目大意
G
r
e
g
Greg
Greg 有一个有边权的有向图,包含
n
n
n 个点。这个图的每两个点之间都有两个方向的边。Greg喜欢用他的图玩游戏,现在他发明了一种新游戏:
游戏包含
n
n
n 步。
第
i
i
i 步Greg从图中删掉编号为
x
i
x_i
xi 的点。当删除一个点时,这个点的出边和入边都会被删除。
在执行每一步之前,
G
r
e
g
Greg
Greg 想知道所有点对间最短路长度的和。最短路可以经过任何没删掉的点。换句话说,如果我们假设
d
(
i
,
v
,
u
)
d(i,v,u)
d(i,v,u) 是在删掉
x
i
x_i
xi 前
v
v
v 和
u
u
u 间的最短路长度,那么
G
r
e
g
Greg
Greg 想知道下面这个求和的值:
帮帮
G
r
e
g
Greg
Greg,输出每一步之前要求的值。
输入格式
第一行包含一个整数
n
(
1
≤
n
≤
500
)
n (1≤n≤500)
n(1≤n≤500) ,代表图中的点数。
下面 n 行每行包含
n
n
n 个整数,代表边权:第
i
i
i 行的第
j
j
j 个数
a
i
a_i
ai
j
_j
j (1≤
a
i
a_i
ai
j
_j
j≤
1
0
5
10^5
105,
a
i
a_i
ai
i
_i
i=0) 代表从
i
i
i 到
j
j
j 的边权。
最后一行包含
n
n
n 个整数:
x
1
x_1
x1,
x
2
x_2
x2,…,
x
n
x_n
xn (1≤
x
i
x_i
xi≤n) ,分别为Greg每一步删掉的点的编号。
输出格式
输出
n
n
n 个整数,第
i
i
i 个数等于游戏的第
i
i
i 步之前统计的求和值。
请不要在
C
+
+
C++
C++中使用 %lld 标志来输出64位整数
l
o
n
g
l
o
n
g
long long
longlong,推荐使用
c
i
n
,
c
o
u
t
cin, cout
cin,cout 流或者用 %I64d 标志。
输入样例
4
0 3 1 1
6 0 400 1
2 4 0 1
1 1 1 0
4 1 2 3
输出样例
17 23 404 0
倒着套Floyed 在每个步骤中,我们尝试通过顶点K传递路径。我们不会删除顶点,而是会添加(从末尾开始)。在每一步中,我们将尝试通过所有新顶点在所有顶点之间运行路径。记录下删除点的信息,再倒着添加回去,在这个过程中套一个 Floyd 进去,要注意的是累计答案的时候判断点是否存在。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=510;
ll mp[maxn][maxn],ans[maxn],a[maxn];
bool v[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j) scanf("%I64d",&mp[i][j]);
for(int i=1;i<=n;++i) scanf("%I64d",&a[i]);
for(int k=n;k;--k){
v[a[k]]=true; //加入点
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
mp[i][j]=min(mp[i][j],mp[i][a[k]]+mp[a[k]][j]);
if(v[i] && v[j]) //判断两个点是否已经存在
ans[k]+=mp[i][j]; //累计最短路之和
}
}
}
for(int i=1;i<=n;++i){
if(i!=1) printf(" ");
printf("%I64d",ans[i]);
}
return 0;
}