题意:
有n个村庄,村庄间有m条公路,一次地震将连向每个村庄的公路损坏,所以要进行维修,后面有q个询问,问是在第几天的时候从x村庄到y村庄我们是否能到达,如果能到达的最小距离是多少。
典型的多源汇最短问题,我们要采用Floyd算法进行求解。
首先我们先了解一下什么事Floyd算法:
g(i,j) 表示节点i到j最短路径的距离,对于每一个节点k,检查g(i,k) +g(k,j) 小于g(i,j) 如果成立,g(i,j) =g(i,k) +g(k,j);遍历每个k,每次更新的是除第k行和第k列的数。第1步:初始化g矩阵。
矩阵中g[i][j]的距离为顶点i到顶点j的权值;如果i和j不相邻,则g[i][j]=∞。
如果i==j,则g[i][j]=0;
for(int k = 0; k < n; k ++)//k是中转点,i是起点,j是终点
for(int i = 0; i < n; i ++)
for(int j = 0; j < n; j ++)
if(g[i][j] > g[i][k] + g[k][j])
g[i][j] = g[i][k] + g[k][j];
而本题最大区别就是我们不能随意去用中转点,因为在第i天的时候你只有前i个村庄才能到达,所以我们的中转点需要特殊处理,不能遍历从1~n;
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 250;
int n, m;
int g[N][N];
int arr[N];
inline void floyd(int x)
{
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < n; j ++)
{
if(g[i][j] > g[i][x] + g[x][j])
g[i][j] = g[i][x] + g[x][j];
}
}
return;
}
int main()
{
IOS;
cin >> n >> m;
for(int i = 0; i < n; i ++) cin >> arr[i];
for(int i = 0; i < n; i ++)
for(int j = 0; j < n; j ++)
g[i][j] = 1e9;//初始化
for(int i = 0; i < n; i ++)
g[i][i] = 0;//到自身的距离为0
while(m--)
{
int a, b, c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = c;//存图
}
int q;
cin >> q;
int now = 0;
while(q--)
{
int a, b, c;
cin >> a >> b >> c;
while(arr[now] <= c && now < n)//特别注意中转的点处理
{
floyd(now);
now++;
}
//cout << now << " >> " << endl;
if(arr[a] > c || arr[b] > c) cout << -1 << '\n';//想要到达的或者出发的点没有修好
else
{
if(g[a][b] == 1e9) cout << -1 << '\n';//没有连通
else cout << g[a][b] << '\n';
}
}
return 0;
}