UVALive - 4618 Wormholes(负环)

题目大意:给出出发点和终点和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\n", 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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-13 16:32:04

UVALive - 4618 Wormholes(负环)的相关文章

Poj 3259 Wormholes 负环判断 SPFA &amp; BellmanFord

#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <

[USACO06DEC]虫洞Wormholes (负环模板)

题意::问一个图是否存在负环,虫洞一边的权值为负 思路: dfs版spfa判环根据:若一个节点出现2次及以上,则存在负环.(你可以假想一下,当一个点被搜过时,再次深搜的话还能搜索到那不就说明存在负环嘛可能解释的不好,请见谅) {补充bfs版本:若一个节点入队列的次数超过n,则存在负环.} 如果是bfs来实现的话,果断到达上限(T-L-E),而dfs版的话,就相对快一些. 对于本题的强大数据来说,还需加入一定的优化: 由于是负环,所以无需像一般的spfa一样初始化为极大的数,只需要初始化为0就够了

ACM: POJ 3259 Wormholes - SPFA负环判定

POJ 3259 Wormholes Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way pa

poj 3259 Wormholes 【SPFA&amp;amp;&amp;amp;推断负环】

Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 36852   Accepted: 13502 Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way p

UVA558 - Wormholes(BellmanFord判负环)

UVA558 - Wormholes 题目大意: 有一个教授希望利用虫洞回到过去(还是从这个虫洞出来就到达了过去),给你虫洞形成的有向图,问教授能否回到过去. 解题思路: 利用BellmanFord判负环,如果不存在负环的话,那么最多经过N - 1次迭代就可以得到最短路,因为形成最短路最多N - 1个节点(起点不算),但是如果存在了负环,那么就可以一直迭代,最短路会越来越小.可以利用这个性质来判断是否存在负环. 代码: #include <cstdio> #include <cstrin

(简单) POJ 3259 Wormholes,SPFA判断负环。

Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Eac

POJ 3259 Wormholes (判负环)

Wormholes Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 46123 Accepted: 17033 Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path

poj3259 Wormholes --- spfa判负环

又写了个bellman模板一直RE求解啊... #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x

uva558 Wormholes SPFA 求是否存在负环

J - Wormholes Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Description In the year 2163, wormholes were discovered. A wormhole is a subspace tunnel through space and time connecting two star systems. Wormholes