luogu解题报告:P1119灾后重建【图论/最短路】
分析
看到此题,第一反应是堆优化dijkstra解决问题,但询问过多会导致TLE。看数据范围:
看Floyd算法代码:
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dis[i][j] = dis[j][i] = min(dis[i][j], dis[i][k] + dis[k][j]);
事实上,Floyd算法是基于动态规划的。根据《算法导论》设
目标为:
而我们通常所见到的Floyd算法则使用了类似滚动数组的思想,因此k需要放到最外层循环。
既然k表示的是以前k个村庄为中转点的最短路径,而题目中被损坏的村庄根据修复先后排了序,询问也按照时间先后拍排了序,那么不难想到,在做Floyd的过程中,可以先进行一个判断:如果当前的k被修复的时间已经超出了询问给定的时间(即前k-1个村庄被修复恰好是该询问所需的情况),且两个顶点也被修复了,那么
实例代码
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int g[205][205], n, m;
int t[205];
int from[50005], to[50005], timen[50005];
int main()
{
cin >> n >> m;
memset(g, 127/3, sizeof g);
for (int i = 1; i <= n; i++) {
g[i][i] = 0;
cin >> t[i];
}
for (int i = 1; i <= m; i++) {
int a, b, c;
cin >> a >> b >> c;
a++; b++;
g[a][b] = g[b][a] = c;
}
int q;
cin >> q;
for (int i = 1; i <= q; i++) {
cin >> from[i] >> to[i] >> timen[i];
from[i]++; to[i]++;
}
int ln = 1;
for (int k = 1; k <= n; k++) {
for (; ln <= q && timen[ln] < t[k]; ln++) {
if (t[from[ln]] >= t[k] || t[to[ln]] >= t[k]
|| g[from[ln]][to[ln]] >= 233333333)
cout << -1 << endl;
else
cout << g[from[ln]][to[ln]] << endl;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = g[j][i] = min(g[i][j], g[i][k]+g[k][j]);
}
for (; ln <= q; ln++) {
if (g[from[ln]][to[ln]] >= 233333333)
cout << -1 << endl;
else
cout << g[from[ln]][to[ln]] << endl;
}
return 0;
}