luogu解题报告:P1119灾后重建【图论/最短路】

题目及描述见https://www.luogu.org/problem/show?pid=1119

分析

看到此题,第一反应是堆优化dijkstra解决问题,但询问过多会导致TLE。看数据范围:N200,这是一个很明显的提示:Floyd算法。Floyd算法看起来并不如SPFA和Dijkstra适合魔改,但事实上,这是我们对Floyd理解不深入引发的错觉。

看Floyd算法代码:

for (int k = 1; k <= n; k++)
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            dis[i][j] = dis[j][i] = min(dis[i][j], dis[i][k] + dis[k][j]);

事实上,Floyd算法是基于动态规划的。根据《算法导论》设dkij表示i到j,所有中间节点取自[1,n]N的最短路径的权重,容易写出动态转移方程:

dkij={wij,k=0,min(d(k1)ij,d(k1)ik+d(k1)kj),k1

目标为:

dnij

而我们通常所见到的Floyd算法则使用了类似滚动数组的思想,因此k需要放到最外层循环。

既然k表示的是以前k个村庄为中转点的最短路径,而题目中被损坏的村庄根据修复先后排了序,询问也按照时间先后拍排了序,那么不难想到,在做Floyd的过程中,可以先进行一个判断:如果当前的k被修复的时间已经超出了询问给定的时间(即前k-1个村庄被修复恰好是该询问所需的情况),且两个顶点也被修复了,那么dis[i][j]=d(k1)ij为所求的,在当前时间条件下的最短路径。

实例代码

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

int g[205][205], n, m;
int t[205];
int from[50005], to[50005], timen[50005];

int main()
{
    cin >> n >> m;
    memset(g, 127/3, sizeof g);
    for (int i = 1; i <= n; i++) {
        g[i][i] = 0;
        cin >> t[i];
    }
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        a++; b++;
        g[a][b] = g[b][a] = c;
    }
    int q;
    cin >> q;
    for (int i = 1; i <= q; i++) {
        cin >> from[i] >> to[i] >> timen[i];
        from[i]++; to[i]++;
    }
    int ln = 1;
    for (int k = 1; k <= n; k++) {
        for (; ln <= q && timen[ln] < t[k]; ln++) {
            if (t[from[ln]] >= t[k] || t[to[ln]] >= t[k]
            || g[from[ln]][to[ln]] >= 233333333)
                cout << -1 << endl;
            else
                cout << g[from[ln]][to[ln]] << endl;
        }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                g[i][j] = g[j][i] = min(g[i][j], g[i][k]+g[k][j]);
    }
    for (; ln <= q; ln++) {
        if (g[from[ln]][to[ln]] >= 233333333)
            cout << -1 << endl;
        else
            cout << g[from[ln]][to[ln]] << endl;
    }
    return 0;
}
posted @ 2016-10-23 19:02  ljt12138  阅读(178)  评论(0编辑  收藏  举报