洛谷 P6464 【传送门】
期末考前一天发题解求 \(rp\) 。
这道题一看数据范围 \(n≤100\) 。暴力石锤了。
很容易想到 \(Floyd\) 。
先算未建传送门时的最短路。接着两所学校两所学校枚举,求建传送门的最优方案。
要开两个数组,
int f[101][101];
int F[101][101];
\(f[i][j]\) 表示未建传送门时的 \(i\) 到 \(j\) 的最短路。
\(F[i][j]\) 表示建了传送门之后 \(i\) 到 \(j\) 的最短路。
该上代码了~
#include<bits/stdc++.h>
#define FOR(i,j,k) for(int i=(j);i<=(k);i++)
using namespace std;
int n,m;
int f[101][101];
int F[101][101];
inline void back()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
F[i][j]=f[i][j];
}
int main()
{
scanf("%d%d",&n,&m);
memset(f,-1,sizeof(f));
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(f[u][v]==-1||f[u][v]>w) f[u][v]=f[v][u]=w;//建边,防重边(不过数据里没有)
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(f[i][k]!=-1&&f[k][j]!=-1)
if(f[i][j]==-1||f[i][j]>f[k][j]+f[i][k])
f[i][j]=f[i][k]+f[k][j];//Floyd
int ans=2e9;//较大值
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)//暴力枚举
{
back();//先让F数组还原成f数组
F[i][j]=F[j][i]=0;//在教学楼 i 和 j 之间建立传送门
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
if(F[x][y]==-1||F[x][y]>F[x][i]+F[i][y])
F[x][y]=F[x][i]+F[i][y];//Floyd
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
if(F[x][y]==-1||F[x][y]>F[x][j]+F[j][y])
F[x][y]=F[x][j]+F[j][y];//Floyd
int res=0;
for(int x=1;x<=n;x++)
for(int y=1;y<x;y++)
res+=F[x][y];
ans=min(res,ans);
}
printf("%d\n",ans);
return 0;
}
为什么这里 \(↓\) 要这么算呢
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
if(F[x][y]==-1||F[x][y]>F[x][i]+F[i][y])
F[x][y]=F[x][i]+F[i][y];
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
if(F[x][y]==-1||F[x][y]>F[x][j]+F[j][y])
F[x][y]=F[x][j]+F[j][y];
因为建立了传送门,只有使用传送门才会影响当前最短路。
\(❀\) 完结撒花 \(❀\)

浙公网安备 33010602011771号