P1119 灾后重建
历程
- 裸dijkstra \(O(QN^2)\),TLE
- 堆优化dijkstra \(O(QMlogN)\),TLE
- floyd \(O(QN^3)\),TLE
- floyd第一次优化 $O(QN^3) $, TLE
- floyd第二次优化 \(O(N^3)\), WA
- floyd第二次优化改写 \(O(N^3)\), AC
开始妄想用dijkstra堆优化水过,结果T了。。。
题意
给出n个受损村庄分别编号0~n - 1,所有村庄同时开始修,给出每一个村庄的维修时间,接下来进行q次询问(超时的原因),每次询问给出(x, y, t),需要输出在t天的时候x和y之间的最短距离。
floyd算法
floyd算法用的是动态规划的思路。

floyd算法可以用来求:在任意一个中转点k(k = 0~n - 1)之下,图的任意两点之间的最短路,自然用floyd就可以求在前k个点作为中转点的影响下的最短距离。
思路
由于本题村庄0~n - 1的维修时间是递增的,并且q个顺序给出的查询中的时间也是递增的,所以可以根据询问所给出的时间t,用floyd将所有维修时间小于等于t的村庄之间的最短距离更新一下,直到t比n - 1号村庄的时间还大为止。
也就是说会根据询问给出的时间t,查看新加入了哪些点,依次用这些点去更新最短距离,直到n个点全部加完。
#include<iostream>
#include<cstring>
using namespace std;
const int N = 210, INF = 0x3f3f3f3f;
int g[N][N];
int t[N];
int n, m, q;
int main(){
memset(g, 0x3f, sizeof g);
cin >> n >> m;
for(int i = 0; i < n; i ++){
cin >> t[i];
g[i][i] = 0;
}
while(m --){
int a, b, w;
cin >> a >> b >> w;
g[a][b] = g[b][a] = w;
}
cin >> q;
int k = 0;
while(q --){
int x, y, tt;
cin >> x >> y >> tt;
while(k < n && t[k] <= tt){
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 ++;
}
if(g[x][y] == INF || t[x] > tt || t[y] > tt) puts("-1");// 这里注意要特判,t[x]和t[y]和tt的关系,因为可能会把g[x][y]更新小了
else cout << g[x][y] << endl;
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步