杭电牢房2022 H题:path

博客主要介绍了图论中的HPath问题,这是一种特殊的最短路问题。在单向图中,存在普通路径和特殊路径,特殊路径允许跳跃到不相邻的节点,代价可能减少。作者通过使用优先队列和BFS算法解决了这个问题,并给出了详细的代码实现。文章还提到了一位知乎博主的题解对其解题思路的帮助。
摘要由CSDN通过智能技术生成

比赛地址nbhttps://acm.hdu.edu.cn/contest/login?cid=1044&redirect=/contest/problems%3Fcid%3D1044

H Path

题目大意:给你一张单向图,存在两种路径一中是普通的带权路,还有一种特殊路径,经过特殊路径后可以飞往与特殊路径不相邻的任意一点,或经过相邻路径且减少k的代价。

作法:用set储存没有确定最短路的点,对于非相邻点我们可以直接更新,相邻点则让边权减去k然后正常做最短路。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <queue>

using namespace std;
using ll = long long;
const int N = 1e6+10, M = N;
const ll INF = 1e18;
int h[N], e[M], w[M], ne[M], type[M], idx;

struct Node {
    ll id, dis, type;

    bool operator<(const Node &t) const {
        return dis > t.dis;
    }//优先队列存结构体只能重构<
};

bool st[N][2];
ll dist[N][2];
int close[N];//用来标记领边
void add(int a, int b, int c, int d) {
    e[idx] = b, w[idx] = c, type[idx] = d, ne[idx] = h[a], h[a] = idx++;
}

int n, m, s, k;

void BFS() {
    set<int> S;//S中存还未确定最短路的点
    for (int i = 1; i <= n; i++) {
        if (i != s) S.insert(i);
        st[i][0] = st[i][1] = false;
        dist[i][0] = dist[i][1] = INF;
    }
    dist[s][0]=0;
    priority_queue<Node>q;
    q.push({s,0,0});
    int cnt=0;
    while(!q.empty())
    {
        auto t=q.top();
        q.pop();
        int ty=t.type,ver=t.id;
        cnt++;
        if(!ty) S.erase(ver); //如果是正常道路就正常做
        else
        {
            for(int i=h[ver];~i;i=ne[i])
            {
                int j=e[i];
                close[j]=cnt;   //都是cnt号的领边
            }
            vector<int>tmp;
            for(auto it:S)
            {
                if(close[it]!=cnt)  // 非相邻的点
                {
                    tmp.push_back(it);
                    dist[it][0]=dist[ver][ty];
                    q.push({it,dist[it][0],0});
                }
            }
            for(auto it : tmp) S.erase(it); // 被更新的点被遍历过 所以直接删除
        }

        int y=0;
        if(ty) y-=k;

        if(st[ver][ty]) continue;
        st[ver][ty]=true;

        for(int i = h[ver] ; ~i ; i = ne[i])
        {
            int j = e[i];
            if(dist[j][type[i]] > dist[ver][ty] + w[i] + y)
            {
                dist[j][type[i]] = dist[ver][ty] + w[i] + y;
                q.push({j, dist[j][type[i]], type[i]});
            }
        }
    }

}

void Solve() {
    cin >> n >> m >> s >> k;
    memset(h, -1, sizeof(h));
    memset(close, -1, sizeof(close));
    while (m--) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        add(a, b, c, d);
    }

    BFS();
    for (int i = 1; i <= n; i++)
        if (min(dist[i][0], dist[i][1]) == INF) cout << -1 << " ";
        else cout << min(dist[i][0], dist[i][1]) << " ";
    cout << "\n";
}


int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin >> T;
    while (T--)
        Solve();
}

如果看不懂可以直接看这位大佬的题解,给了我很大帮助

https://zhuanlan.zhihu.com/p/543760351

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值