Greg and Graph:原题链接

题意:

     给你一个有权有向图,图包含n个点,接下来会操作n次,逐渐删除这n个点,并将与该点相关的所有边删除,求输出操作之前图中的所有最短路径的和

题目思路:

     通过题意求所有最短路径的和,可得用Floyd算法去求解。本题主要难点在于如何去解决删点并计算每个时段的最短路径和。      为解决上述问题,可以扭转思维,将删点该为加点的形式,完成Floyd的改变,核心代码如下:

void floyd(){
	//将原先的删除编号数组倒序输出
	//改为对图像进行加点 
	for (int k=n;k>=1;k--)
	{
		//x为加的点 
		long long x=a[k];
		//利用vis记录判断点是否加入
		//标记为1的点为以加入的点 
		vis[x]=1;
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<=n;j++)
			{
				//跳过i,j相等的情况 
				if (i==j)continue;
				//与能将所有点当做跳板的原 Floyd算法不同
				//因为我们是加入点,所以将加入的点当做跳板,即满足遍历所有点,也完成加点,十分巧妙的构思 
				mp[i][j]=min(mp[i][j],mp[i][x]+mp[x][j]);
				//只有当i,j的编号加入图后,才可以加入路径和。
				//利用ans数组记录每个时刻的路径和 
				if (vis[i] && vis[j])ans[k]+=mp[i][j];
			}
		}
	}
	return ;
}

     在理解完核心代码后,基本就能得出AC代码了。

     以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int N=1e3,inf=0x3f3f3f3f;
long long n;
long long a[N*N],vis[N*N],ans[N*N],mp[N][N];

void floyd(){
	//将原先的删除编号数组倒序输出
	//改为对图像进行加点 
	for (int k=n;k>=1;k--)
	{
		//x为加的点 
		long long x=a[k];
		//利用vis记录判断点是否加入
		//标记为1的点为以加入的点 
		vis[x]=1;
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<=n;j++)
			{
				//跳过i,j相等的情况 
				if (i==j)continue;
				//与能将所有点当做跳板的原 Floyd算法不同
				//因为将我们是加入点,所以将加入的点当做跳板,即满足遍历所有点,也完成加点,十分巧妙的构思 
				mp[i][j]=min(mp[i][j],mp[i][x]+mp[x][j]);
				//只有当i,j的编号加入图后,才可以加入路径和。
				//利用ans数组记录每个时刻的路径和 
				if (vis[i] && vis[j])ans[k]+=mp[i][j];
			}
		}
	}
	return ;
}


int main(){
	cin >>n;
	//读入各点 
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=n;j++)cin >>mp[i][j];
	}
    //读入删点编号
	for (int i=1;i<=n;i++)cin >>a[i];
	floyd();
	//虽然我们原先是倒序输入,但ans记录的已经是倒序时的路径和,所以正序输出即可 
	for (int i=1;i<=n;i++)cout <<ans[i]<<' ';
	cout <<"\n";
}