【Floyd】灾后重建

131 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1️⃣题目描述

题目链接:
www.luogu.com.cn/problem/P11…

在这里插入图片描述

这道题良心的是重建的时间是从小到大排序的,而且询问的重建时间也是从小到大排序的,所以我们可以正向的进行操作,不需要进行排序操作。


2️⃣简单思路

本题主要是Floyd算法本质的一个理解和练习。

Floyd算法中的k表示的是中间节点,以此为中间节点可以更新两点之间的最短距离。

f[i][j]f[i][j]:代表的是ij的最短距离 每当进行一个询问时,如果有村庄在此询问的时间点之前重建完成,就要以此村庄为中转节点,对所有点的最短距离进行更新。

更新的代码:

while(a[k] <= t && k < n)
{
	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
		{
			if(f[i][k] + f[k][j] < f[i][j])
				f[j][i] = f[i][j] = f[i][k] + f[k][j];
		}
	k ++;
}

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int n, m;
	cin >> n >> m;
	vector<int> a(n);
	for(int i = 0; i < n; i++) cin >> a[i];
	
	vector f(n, vector(n, 1e9));
	 	
	for(int i = 0; i < n; i++)	f[i][i] = 0;
	for(int i = 1; i <= m; i++)
	{
		int a, b, c;
		cin >> a >> b >> c;
		f[a][b] = f[b][a] = c;
	}
	int q;
	int k = 0;
	cin >> q;
	while(q--)
	{
		int x, y, t;
		cin >> x >> y >> t;
		
		while(a[k] <= t && k < n)
		{
			for(int i = 0; i < n; i++)
				for(int j = 0; j < n; j++)
				{
					if(f[i][k] + f[k][j] < f[i][j])
						f[j][i] = f[i][j] = f[i][k] + f[k][j];
				}
			k ++;
		}
		
		if(a[x] > t || a[y] > t) cout << -1 << "\n";
		else 
		{
			if(f[x][y] == 1e9) cout << -1 << "\n";
			else cout << f[x][y] << "\n";
		} 
		
	}
	
	return 0;
}