LuoguP1119 灾后重建

Description

有N个村庄,村庄编号从0到N−1,M条公路,公路是双向的。并给出第i个村庄重建完成的时间t_i,你可以认为是同时开始重建并在第t_i 天重建完成,并且在当天即可通车。若t_i为0则说明地
震未对此地区造成损坏,一开始就可以通车。之后有Q个询问(x, y, t),对于每个询问你要回答在第t天,从村庄x到村庄y的最短路径长度为多少。如果无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未重建完成 ,则需要返回-1。

Analysis

这道题考察floyd的本质,若用朴素的floyd,循环Q次,每次都要跑O(N3)的Floyd,则复杂度为O(N3Q)。这里其实不需要枚举最外层循环k,如果在某个时间t,找到一个_T[k] <= t,则将其作为中间点更新最短距离。这样每次询问都找到时间小于t的k,k不断自加,最终时间复杂度O(N^3 + Q)。(我也不知道为什么T[]不排序也可以AC)

Code

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#define N 210
using namespace std;
int G[N][N],T[N],_T[N],n,m,q,x,y,t,k;
void floyd(){
// P.S. 我就是忘了 k < n只得了40分
//因为T初始为0
//当然也可以初始化T[n] = inf就不用判断了
while(T[k] <= t && k < n){
for(int i = 0;i < n;++i){
for(int j = 0;j < n;++j){
G[i][j] = min(G[i][j],G[i][k] + G[k][j]);
}
}
++k;
}
}
void solve(){
floyd();
if(T[x] > t || T[y] > t || G[x][y] == 0x3f3f3f3f) printf("-1\n");
else printf("%d\n",G[x][y]);
}
int main()
{
scanf("%d%d",&n,&m);
memset(G,0x3f,sizeof(G));
for(int i = 0;i < n;++i){
G[i][i] = 0;
scanf("%d",&T[i]);
}
for(int i = 1;i <= m;++i){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[u][v] = G[v][u] = w;
}
scanf("%d",&q);
for(int i = 1;i <= q;++i){
scanf("%d%d%d",&x,&y,&t);
solve();
}
return 0;
}
posted @   Zforw  阅读(30)  评论(0编辑  收藏  举报
编辑推荐:
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
阅读排行:
· 《HelloGitHub》第 106 期
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· 深入理解Mybatis分库分表执行原理
· 使用 Dify + LLM 构建精确任务处理应用
点击右上角即可分享
微信分享提示