灾后重建
灾后重建
P1119 灾后重建 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
floyd
本题考查 floyd 算法的本质:
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
f[i][j] = min(f[i][j], f[i][k] + f[k][j])
第一层循环 k 表示 i 号点 只能经过 1 - k 号点中转 到达 j 号点的最短距离
因此本题求解各个询问的过程相当于把 floyd 拆解出来,每当一个点被重建,意思为可以经过这个点中转更新最短距离,由于询问和点的重建时间都是非递减顺序,因此第 1 个点重建,就是 k = 1 跑一次后两层循环;第 2 个点重建,就是 k = 2 跑一次后两层循环 。。。
因此所有点重建的更新过程相当于只跑了一遍完整的 floyd,复杂度为 \(O(n^3+q)\)
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 2e2 + 10;
const int INF = 0x3f3f3f3f;
int n, m;
int g[N][N];
int a[N];
void updata(int now)
{
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
g[i][j] = min(g[i][j], g[i][now] + g[now][j]);
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 0; i < n; i++)
cin >> a[i];
memset(g, 0x3f, sizeof g);
for (int i = 0; i < n; i++)
g[i][i] = 0;
while(m--)
{
int i, j, w;
cin >> i >> j >> w;
g[i][j] = g[j][i] = w;
}
int q;
cin >> q;
int now = 0;
while(q--)
{
int x, y, t;
cin >> x >> y >> t;
while(a[now] <= t && now < n)
{
updata(now);
now++;
}
if (a[x] > t || a[y] > t)
cout << -1 << endl;
else
{
if (g[x][y] == INF)
cout << -1 << endl;
else
cout << g[x][y] << endl;
}
}
return 0;
}