zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    转:浅谈深度学习(Deep Learning)的基本思想和方法
    随记:我们需要怎样的数学教育?
    转 :hlda文献学习笔记
    转:关于Latent Dirichlet Allocation及Hierarchical LDA模型的必读文章和相关代码
    推荐算法相关总结表(包括DM)
    转 自己动手写推荐系统
    求熵 python 代码
    特征值与特征向量
    转: 谱聚类
    链接数据库
  • 原文地址:https://www.cnblogs.com/ljt12138/p/6684368.html
Copyright © 2011-2022 走看看