• UVALive


    题目大意:给出出发点和终点和m个虫洞(虫洞的出发点。终点,生成时间和花费时间)。问从起点到终点花费的最小时间

    解题思路:关键是有负环,所以直接跑最短路算法的话会TLE。所以负环要处理一下
    可是这个负环又不是负环。由于负环到一定程度的话。就会消失。
    比方。到达时间小于虫洞的生成时间,那么负环就消失了。也就是说,负环内的点满足的最优情况就是到达时间刚好等于生成时间
    所以,先找出负环,接着推断一下这个负环内的能节省的最多时间。然后将全部点都减去那个时间,那么负环就消失了
    详细看代码

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    
    #define N 110
    #define INF 0x3f3f3f3f
    
    struct Point{
        int x, y, z;
    }s1, s2;
    
    struct wormhole{
        Point s, t;
        int start, cost;
    }W[N];
    
    int n, source, sink;
    int dis[N][N];
    
    int distance(int i, int j) {
        int x = W[i].t.x - W[j].s.x;
        int y = W[i].t.y - W[j].s.y;
        int z = W[i].t.z - W[j].s.z;
        return ceil(sqrt(1.0 * x * x + 1.0 * y * y + 1.0 * z * z));
    }
    
    void init() {
        scanf("%d%d%d%d%d%d%d", &s1.x, &s1.y, &s1.z, &s2.x, &s2.y, &s2.z, &n);
        source = 0;
        sink = n + 1;
        W[0].s = s1;
        W[0].t = s1;
        W[0].start = -INF;
        W[0].cost = 0;
    
        W[sink].s = s2;
        W[sink].t = s2;
        W[sink].start =-INF;
        W[sink].cost = 0;
    
        for (int i = 1; i <= n; i++)
            scanf("%d%d%d%d%d%d%d%d", &W[i].s.x, &W[i].s.y, &W[i].s.z, &W[i].t.x, &W[i].t.y, &W[i].t.z, &W[i].start, &W[i].cost);
    
        //dis[i][j]表示从第i个虫洞的终点走到第j个虫洞的出发点的时间
        for (int i = 0; i <= sink; i++)
            for (int j = 0; j <= sink; j++) 
                dis[i][j] = distance(i, j);
    }
    
    int pre[N], d[N];
    void solve() {
    
        for (int i = 0; i <= sink; i++) {
            d[i] = INF;
            pre[i] = -1;
        }
        d[source] = 0;
    
        while (1) {
            int tmp;
            bool flag = false;
            //找最短路
            for (int i = 0; i <= sink; i++)
                for (int j = 0; j <= sink; j++) {
                    tmp = max(d[i] + dis[i][j], W[j].start) + W[j].cost;
                    if (tmp < d[j]) {
                        d[j] = tmp;
                        pre[j] = i;
                        flag = true;
                    }
                }
    
            //不用更新了
            if (!flag) {
                printf("%d
    ", d[sink]);
                return ;
            }
    
            for (int i = 0; i <= sink; i++) {
                int k = i;
                //推断有没有环
                for (int j = 0; j <= sink && k != -1; j++)  k = pre[k];
                if (k == -1) continue;
                //找出更新的值,破除这个负环,更新的值就是到达起点的值和生成时间的差的最小值。由于在负环内能够等待到生成时间
                int Min = d[pre[k]] + dis[pre[k]][k] - W[k].start;
                for (int j = pre[k]; j != k; j = pre[j])
                    Min = min(d[pre[j]] + dis[pre[j]][j] - W[j].start, Min);
                //假设不存在负环了
                if (Min <= 0) continue;
                //更新负环内的点的距离,破解负环
                    d[k] -= Min;
                for (int j = pre[k]; j != k; j = pre[j])
                    d[j] -= Min;
            }
        }
    }
    
    int main() {
        int test;
        scanf("%d", &test);
        while (test--) {
            init();
            solve();
        }
        return 0;
    }
    
  • 相关阅读:
    CSS实现字母全大写
    人生职业规划与自身设想
    关于人生的一些想法,和淘客SEO的思想。
    保持积极向上的心态去把傻逼的坚持换成牛逼的结果
    SEO站群随想,及自我的认知和想法
    我是SEOer,我为自己代言
    打印出 html结构中的ul li
    js数据类型转换
    js object类型转换 内存泄漏 垃圾回收机制
    页面重置样式reset.css
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/8409089.html
Copyright © 2020-2023  润新知