洛谷 P1119 災後重建 題解
阿新 • • 發佈:2018-10-31
題目大意
給你\(n\)個點建立的時間,然後給你\(m\)條邊,之後有\(q\)個詢問,每次詢問在某一天圖中兩個點之間的最短距離。
題目連結
思路
這個題目中有兩個很關鍵的地方,首先我們可以看到題目中給出每個點建立的時間(即村子修復的時間是遞增的)然後詢問中的天數也是遞增的。所以這樣就大大減少了程式設計難度。因為我們要求任意兩點之間的最短路再加上題目中點的個數那麼小,所以我們可以想到要用Floyd演算法。再Floyd演算法中我們的那三層迴圈中最外層迴圈列舉的那個點的作用相當於在圖中假如這個點,然後再用這個點去優化途中任意兩點間的距離。這與這個題目中點的建立在本質上是一樣的,所以我們列舉到\(k\)
假設我們現在列舉到\(k\)號點,說明\(k\)號點在圖上建立了起來。那麼詢問中詢問時間在\([t[k],t[k + 1])\)之內的詢問都可以回答。然後我們按照題意回答詢問即可。
程式碼
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 2e2 + 5; const int M = 2e4 + 5; const int INF = 0x3f3f3f3f; int n, m, q; int u, v, w; int time_tmp; //要查詢的時間 int t[N]; //每個村莊修復的時間 int matrix[N][N]; int read() { int s = 0, w = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') w = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); } return s * w; } void write(int x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + '0'); } inline int Min(int x, int y) { return x <= y ? x : y; } int main(int argc, char const *argv[]) { memset(matrix, 0x3f, sizeof(matrix)); n = read(), m = read(); for (register int i = 0; i < n; ++i) { t[i] = read(); matrix[i][i] = 0; } for (register int i = 0; i < m; ++i) { u = read(), v = read(), w = read(); matrix[u][v] = Min(matrix[u][v], w); matrix[v][u] = Min(matrix[v][u], w); } q = read(); int pos_start = 0; //從第0個村莊開始修復 for (register int i = 0; i < q; ++i) { u = read(), v = read(), time_tmp = read(); int pos = pos_start; while (pos < n && t[pos] <= time_tmp) //直到修復到可以查詢為止 ++pos; for (register int k = pos_start; k < pos; ++k) { for (register int i = 0; i < n; ++i) { for (register int j = 0; j < n; ++j) { if (matrix[i][j] > matrix[i][k] + matrix[k][j]) matrix[i][j] = matrix[i][k] + matrix[k][j]; } } } if (t[u] > time_tmp || t[v] > time_tmp || matrix[u][v] == INF) { printf("-1\n"); } else { printf("%d\n", matrix[u][v]); } pos_start = pos; } return 0; }