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;
}

posted @ 2021-11-18 17:03  艾特玖  阅读(34)  评论(0)    收藏  举报