前置芝士:
说白了,Floyd本质上就是一个dp:
K为外层状态,i和j为内层枚举。Floyd完整状态其实是:(f[k][i][j])表示以前K个点为转移点(即编号为1~k的点可以被用来松弛),从(i)到(j)的最短路径。
每条最短路径都是以k为基础的,对于未枚举进k的点将不被考虑进最短路径的松弛,k也就作为整个图的最短路径的前提条件,那么自然作为最外层状态转移。
考虑这道题:
给你一张无向图,给你每一个节点的信息t表示当前节点在时间为t以及以后可以到达。
翻译一下,也就是可以考虑进最短路的松弛。
朴素想法,对于每个t,我们可以枚举每一个结点,如果结点的(t>)当前询问的时间,将不被考虑进图中。每一次询问在重新建完图后跑一边Floyd,并在判断起点村庄s到终点l能否到达,如果能到达输出即可。
很明显,T的死死的。每次跑一遍floyd实在是太浪费了时间,而且题目中的数据是递增的。出题人给你的优化条件你怎么能不用呢。
k表示考虑了1~n的节点作为可松弛点,也就是说:编号1到n的节点都能够到达。
换句话说,1到n节点满足了被加入最短路集合的条件。
对于这道题,从暴力思路可以看出,一个节点被加入最短路集合的条件就是当前节点的t值小于等于询问的时间t。而出题人给你的t是单调的。那么,我们设上一次询问的时间为(t_{0}),这一次询问的时间为(t_{1}),以t为floyd最外层状态k,对于(t_{0})之前的k我们就不必再跑一遍了,从上一次能够到达的编号为now的节点开始往后判断节点的t是否小于询问的t,直到大于询问的t为止。
原因很好理解,节点的t随着编号的上升而上升,而询问的t又上升,那么考虑过的节点一定满足加入最短路集合的条件,也就不用再跑一遍Floyd((n^2))的部分了。
核心代码:
q=read();
while(q--)
{
u=read(),v=read(),w=read();
while(now<n&&a[now]<=w)
{
dp(now);//now节点就可以被加入可用来松弛的节点的集合,跑一边floyd
now++;//考虑编号更大的,t值更大的结点。
}
}
\Floyd部分
inline void dp(int now)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][now]+dis[now][j]);
}
}
全部代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
#define re register
using namespace std;
const int N=201;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,a[N],u,w,v,q,judge=-1,dis[N][N],now;
inline void add(int from,int to,int w)
{
dis[from][to]=dis[to][from]=w;
}
inline void dp(int now)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][now]+dis[now][j]);
}
}
int main()
{
n=read(),m=read();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
dis[i][j]=1e9+7;
for(int i=0;i<n;i++)
{
a[i]=read();
}
for(int i=1;i<=m;i++)
{
u=read(),v=read(),w=read();
add(u,v,w);
}
q=read();
while(q--)
{
u=read(),v=read(),w=read();
while(now<n&&a[now]<=w)
{
dp(now);
now++;
}
if(a[u]>w||a[v]>w)printf("%d
",judge);
else
{
if(dis[u][v]==1e9+7)printf("%d
",judge);
else printf("%d
",dis[u][v]);
}
}
return 0;
}
希望看完这篇博文后能够加深各位对Floyd的理解!
完结撒花