P1119 灾后重建
分析
通过简单分析题目,我们知道,我们要计算的就是。
随着不断有点被启用,随之而来的边也逐渐可用的情况下,问在某情况下的两点之间的最小值
本题的重要程度*:提高+/省选-
需要明白Floyd算法的本质才能很好地写出这道题
让我们首先从Floyd算法谈起,这看上去是一个非常简单的代码,实际上它确实也非常简洁。
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j])
e[i][j]=e[i][k]+e[k][j];
算法本质:动态规划,就是通过其他的点进行中转来求的两点之间的最短路。因为我们知道,两点之间有多条路,如果换一条路可以缩短距离的话,就更新最短距离。而它最本质的思想,就是用其他的点进行中转,从而达到求出最短路的目的。
返回来看代码,一句话概括:从i号顶点到j号顶点只经过前k号点的最短路程。
而我们再回头看题意:
所有的边全部给出,按照时间顺序更新每一个可用的点(即修建好村庄),对于每个时间点进行两点之间询问,求对于目前建设的所有村庄来说任意两点之间的最短路
不正好就是Floyd算法中使用前k个节点更新最短路的思维吗?
因此我们的解题思路就显而易见了,按照时间不断的解封新的点。
本题核心
inline void updata(int k){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(f[i][j]>f[i][k]+f[j][k])
f[i][j]=f[j][i]=f[i][k]+f[j][k];//用这个新的更新所有前面的
return;
}
只更新到用前k个点
Ac_Code
#include<bits/stdc++.h>
using namespace std;
const int N = 210,INF = 0x3f3f3f3f;
int a[N],g[N][N];
int n,m;
void update(int idx)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
g[j][i]=min(g[j][i],g[i][idx]+g[idx][j]),g[i][j]=g[j][i];
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i!=j) g[i][j]=INF;
else g[i][j]=0;
while(m--)
{
int u,v,t;
cin>>u>>v>>t;
g[u][v]=g[v][u]=t;
}
int q,idx=0;
cin>>q;
while(q--)
{
int u,v,t;
cin>>u>>v>>t;
while(idx<n&&a[idx]<=t)
{
update(idx);
idx++;
}
if(a[u]>t||a[v]>t) puts("-1");
else
{
if(g[u][v]==INF) puts("-1");
else cout<<g[u][v]<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号