P6464 【传送门】:原题链接

题意:

       传智专修学院里有 n 栋教学楼,有 m 条双向通行道路连接这些教学楼且带有路径长度w,路径不存在重边和自环,且路径保证每个点都可以到达。现在学校想安装一对传送门,安装传送门的两点距离为0。求怎么样可以使任意两点之间的最短路长度总和最小

简单思路:

       通过n的数据大小不超过100,且需要求出任意两点之间的最短路长度总和最小,可得Floyd算法(全源最短路)+暴力枚举最适合本题。

       首先根据题意,我们先对题目通过Floyd算法计算出各个路径在未考虑传送门情况下的短路。 代码如下:

//在使用Floyd算法前必须对mp二维数组进行初始化
void init(){
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=n;j++)
		{
			if (i!=j)mp[i][j]=inf;
		}
	}
}
//基础floyd模板算法模板 
void floyd(){
	for (int k=1;k<=n;k++)
	{
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<=n;j++)
			{
				//注意变量k为跳板,需要放置在最上面。
				//mp[N][N]记录各个路径之间的最短路
				mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
			}
		}
	}
	return ;
}

       在用Floyd算法初步得出未设置传送门的路径后,就可以开始进行愉快的暴力求解了。 代码如下:

	for (int k=1;k<n;k++)
	{
		for (int l=k+1;l<=n;l++)
		{
			//设置res计算在设置传送门后的最短路径。
			int res=0; 
			//遍历各点进行计算。 
			for (int i=1;i<n;i++)
			{
				for (int j=i+1;j<=n;j++)
				{
					//因为设置传送门的两点间距离为0
					//所以当k==i或l==j时直接跳过 
					if (k!=i || l!=j)
					{
						//选择最短路径进行相加。
						//mp[i][j]为未设置传送门前的最短路径
						//mp[i][k]+mp[l][j]为从i点出发通过k到l到达j的路径。
						//即:i->k->l->j
						//mp[i][l]+mp[k][j]同理 
						//该解算是Floyd的另类应用,将传送门替换为原先的k。 
						res+=min(mp[i][j],min(mp[i][k]+mp[l][j],mp[i][l]+mp[k][j]));
					}
				}
			}
            //统计设置传送门后的最短的路径 
			ans=min(ans,res);
		}
	}

       以下是AC代码:

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

const int N=1e3,inf=0x3f3f3f3f;
int n,m;
int mp[N][N];
int ans=inf;
//基础floyd模板算法模板 
void floyd(){
	for (int k=1;k<=n;k++)
	{
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<=n;j++)
			{
				//注意变量k为跳板,需要放置在最上面。
				//mp[N][N]记录各个路径之间的全职 
				mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
			}
		}
	}
	return ;
}

void init(){
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=n;j++)
		{
			if (i!=j)mp[i][j]=inf;
		}
	}
}

int main(){
	cin >>n>>m;
	init();
	for (int i=1;i<=m;i++)
	{
		int from,to,w;
		cin >>from>>to>>w;
        //注意,本题说明为无向有权图,题目重述可能讲述不清,再此发表宇宙安全申明,讲过了啊~(|_|)~
		mp[from][to]=mp[to][from]=w;
	}
	floyd();
	//首先设置数字对(k,l)为传送门的两点,进行遍历。 
	for (int k=1;k<n;k++)
	{
		for (int l=k+1;l<=n;l++)
		{
			//设置res计算在设置传送门后的最短路径。
			int res=0; 
			//遍历各点进行计算。 
			for (int i=1;i<n;i++)
			{
				for (int j=i+1;j<=n;j++)
				{
					//因为设置传送门的两点间距离为0
					//所以当k==i或l==j时直接跳过 
					if (k!=i || l!=j)
					{
						//选择最短路径进行相加。
						//mp[i][j]为未设置传送门前的最短路径
						//mp[i][k]+mp[l][j]为从i点出发通过k到l到达j的路径。
						//即:i->k->l->j
						//mp[i][l]+mp[k][j]同理 
						//该解算是Floyd的另类应用,将传送门替换为原先的k。 
						res+=min(mp[i][j],min(mp[i][k]+mp[l][j],mp[i][l]+mp[k][j]));
					}
				}
			}
			//统计设置传送门后的最短的路径 
			ans=min(ans,res);
		}
	}
	cout <<ans<<"\n";
}