UVa12661 Funny Car Racing(Dijkstra)

文章介绍了如何利用Dijkstra算法处理有时间限制的边,即边在特定时间段内开启和关闭,求解从起点s到终点t的最短路径问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

给定n个点,m条边,起始点s,目标点t,求从起点s到终点t的最短距离。已经道路上的边e是每隔eae_aea秒开启,再隔ebe_beb秒关闭,通过时间为ete_tet

思路

在计算边euve_{uv}euv从u到v的时间时,用dud_udu表示到达u时的时间,如果(du mod (ea+eb))+et<ea(d_u \bmod (e_a+e_b)) + e_t < e_a(dumod(ea+eb))+et<ea,则dv=du+etd_v = d_u + e_tdv=du+et,否则dv=du−(du mod (ea+eb))+ea+eb+etd_v=d_u - (d_u \bmod(e_a+e_b)) + e_a + e_b + e_tdv=du(dumod(ea+eb))+ea+eb+et

代码

#include <bits/stdc++.h>

using namespace std;

#define _for(i, a, b) for(int i = (a); i < (b); i++)
#define _rep(i, a, b) for (int i = (a); i <= (b); i++)

struct Edge
{
    int from, to, dist, open, close;
};

struct HeapNode
{
    int u, d;

    bool operator<(const HeapNode& other) const
    {
        return d > other.d;
    }
};



template <size_t SZV, int INF>
struct Dijkstra
{
    int n;
    bool done[SZV];
    vector<Edge> edges;
    vector<int> graph[SZV];
    int d[SZV];
    int p[SZV];

    void init(int n)
    {
        this-> n = n;
        _for(i, 0, n) {
            graph[i].clear();
        }
        edges.clear();
    }

    void addEdge(int from, int to, int w, int open, int close)
    {
        graph[from].push_back(static_cast<int>(edges.size()));
        edges.push_back((Edge){from, to, w, open, close});
    }

    void dijkstra(int s)
    {
        priority_queue<HeapNode> pq;
        fill_n(done, n, false);
        fill_n(d, n, INF);
        d[s] = 0;
        pq.push({s, 0});

        while (!pq.empty()) {
            HeapNode curNode = pq.top();
            pq.pop();

            int u = curNode.u;
            if (done[u]) {
                continue;
            }

            done[u] = true;
            _for(i, 0, static_cast<int>(graph[u].size())) {
                Edge& edge = edges[graph[u][i]];
                int newDist = arrive(d[u], edge);
                if (newDist < d[edge.to]) {
                    d[edge.to] = newDist;
                    pq.push((HeapNode){edge.to, newDist});
                }
            }


        }
    }

    int arrive(int d, const Edge& edge)
    {
        int k = d % (edge.open + edge.close);
        if (k + edge.dist <= edge.open) {
            return d + edge.dist;
        }

        return d - k + edge.open + edge.close + edge.dist;
    }
};



void fastio()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
}

const int MAXN = 305;
const int INF = 1e6;

static Dijkstra<MAXN, INT_MAX> solver;

int main()
{
    fastio();

    #ifndef ONLINE_JUDGE
        ifstream fin("f:\\OJ\\uva_in.txt");
        streambuf* back = cin.rdbuf(fin.rdbuf());
    #endif

    int kase = 1;
    int n, m, s, t;
    while (cin >> n >> m >> s >> t) {
        solver.init(n + 1);

        _for(i, 0, m) {
            int u, v, a, b, w;
            cin >> u >> v >> a >> b >> w;
            if (w > a) {
                continue;
            }

            solver.addEdge(u, v, w, a, b);
        }


        solver.dijkstra(s);
        cout << "Case " << kase++ << ": " << solver.d[t] << endl;
    }


    #ifndef ONLINE_JUDGE
        cin.rdbuf(back);
    #endif

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kgduu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值