题意:n个点的有向带权完全图,第i次删除一个点及其所有的边,
n<=500,求删除xi之前,任意两点最短距离的累加和, ?
逆着考虑:相当于每次添加一个结点后,在更新最短路径.O(n^3)
对第m个新加入的点x,n^2更新x(出发/结尾)时中间点编号为后m+1个的d^(m+1)值 在n^2更更新中间点为x时的d^m值即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps=1e-10;
const int inf=0x3f3f3f3f;
const int N=5e2+20;
ll g[N][N],d[N][N],n,a[N];
vector<ll> ans;
void solve()
{
ans.clear();
ans.push_back(0);
int m=1;
while(m<n)
{
ll res=0;
for(int k=n-m;k<=n;k++)
{
for(int i=n-m;i<=n;i++)
{
int u=a[k],v=a[i],x=a[n-m];
d[x][v]=min(d[x][v],d[x][u]+d[u][v]);
d[v][x]=min(d[v][x],d[v][u]+d[u][x]);
}
}
for(int i=n-m;i<=n;i++)
{
for(int j=n-m;j<=n;j++)
{
int u=a[i],v=a[j],x=a[n-m];
d[u][v]=min(d[u][v],d[u][x]+d[x][v]);
res+=d[u][v];
}
}
m++;
ans.push_back(res);
}
for(int i=ans.size()-1;i>=0;i--)
printf("%I64d ",ans[i]);
printf("\n");
}
int main()
{
while(cin>>n)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%I64d",&d[i][j]);
for(int i=1;i<=n;i++)
scanf("%I64d",&a[i]);
solve();
}
return 0;
}