做一个替我们首先要明确一下数据范围,n《=200,说明n^3的算法是可以过得,而且这个题很明显是一个图论题, 所以我们很容易想到这个题可以用folyd, 但是我在做这个题的时候因为没有深刻理解folyd的意义,因此导致调试了好几小时,
folyd 的思想是dp,我们可以用表示和之间可以通过编号为的节点的最短路径。
初值为原图的邻接矩阵。
则可以从转移来,表示到不经过这个节点。
也可以从转移过来,表示经过这个点。
意思即
然后你就会发现最外层一维空间可以省略,因为只与有关。
虽然这个算法非常简单,但也需要找点时间理解这个算法,就不会再有这种问题啦。因此我们在dp循环的时候可以使用滚动数组,可以节约点空间。
这时候我们就可以看回原题了,我们可以先想比较暴力点的算法,就是直接采用floyd,不加任何优化,这样会很慢,因此我们可以寻找可以优化的方法,比如题目中的时间是递增的,因此我们每次状态转移的时候并不用每次都从第一个点找,而是可以接着上一次的询问。
这样题目就一目了然了。
坑点:他的编号都是从0开始的,且初始化数组的时候不能开太大,否则会爆
代码:
#include <iostream> #include <cstring> #include <algorithm> #include <cstdlib> #include <cstdio> #define M 550 using namespace std; int n, m, dis[M][M], t[M], now, ha, k; int main() { scanf("%d%d", &n, &m); for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) { dis[i][j] = 214748364; } for(int i = 0; i < n; i++) scanf("%d", &t[i]); for(int i = 1; i <= m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); dis[a][b] = c; dis[b][a] = c; } scanf("%d", &ha); for(int g = 1; g <= ha; g++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); for(k = now; k < n; k++) { if(t[k] > c) break; else for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } now = k++; if(dis[a][b] != 214748364 && t[a] <= c && t[b] <= c) printf("%d ", dis[a][b]); else printf("-1 "); } }