Greg and Graph
这题是每次删一次点并输出操作前的值,将其转化成删掉所有点然后依次存入一个点,再进行佛罗里达,最后将值倒过来输出就好
点击查看代码
/* 台州第一深情 */
#include <bits/stdc++.h>
using namespace std;
using i64 = long;
using ll = long long;
typedef pair<int, int> PII;
const int N = 5e2 + 5;
const int M = 1e6;
int vis[M];//vis:判断当前点是否添加进去了
int s, f;
ll a[N][N], b[M];
int n, m;
int p[N];//依次存入需要进行操作的点
ll ans[N];//存值
void build()
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i == j)
{
a[i][j] = 0;
}
else
{
a[i][j] = 1e7;
}
}
}
}
void floyd()
{
for (int tiao = 1; tiao <= n; tiao++)
{
for (int from = 1; from <= n; from++)
{
for (int to = 1; to <= n; to++)
{
a[from][to] = min(a[from][tiao] + a[tiao][to], a[from][to]);
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> a[i][j];//有向图存单边值
}
}
for (int i = 1; i <= n; i++)
{
cin >> p[i];
vis[p[i]]++;//存入点,假装这些点从来没有过
}
for (int i = n; i >= 1; i--)//因为是输入时是顺序删除,所以要倒过来存点
{
vis[p[i]] = 0;//当前点加进来了
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
a[j][k] = min(a[j][k], a[j][p[i]] + a[p[i]][k]);//否罗里达,将存入的点当成跳点,然后进行最小值判断
if (!vis[k] && !vis[j])
{
ans[i] += a[j][k];//如果当前两个点都已经加进来了,就把他们存入当前操作的ans来
}
}
}
}
for (int i = 1; i <= n; i++)//存点是倒过来存,输出要正序输出
{
cout << ans[i] << ' ';
}
return 0;
}