• NC26257 小雨坐地铁 分层图+虚拟源点


    题目描述
    小雨所在的城市一共有 m 条地铁线,分别标号为 1 号线,2 号线,……,m 号线。整个城市一共有 n 个车站,编号为 1∼n 。其中坐 i 号线需要花费 a i a_i ai 的价格,每坐一站就需要多花费 b i b_i bi的价格。i 号线有 c i c_i ci个车站,而且这 c i c_i ci个车站都已知,如果某一站有多条地铁线经过,则可以在这一站换乘到另一条地铁线,并且能多次换乘。现在小雨想从第 s 个车站坐地铁到第 t 个车站,地铁等待时间忽略不计,求最少花费的价格,若不能到达输出 -1 。(地铁是双向的,所以 s 可能大于 t)

    输入描述:
    第一行输入四个正整数 n,m,s,t,分别表示车站个数,地铁线数,起点站和终点站。
    第二行到第 m + 1 行,每行前三个数为 a i a_i ai, b i b_i bi, c i c_i ci, 分别表示坐 i 号线的价格,i 号线每坐一站多花的价格,i 号线车站个数。接下来 c i c_i ci个数,表示 i 号线的每一个车站的编号,单调递增。
    输入:

    5 2 1 4
    2 2 3 1 3 5
    2 1 4 2 3 4 5
    1
    2
    3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出:

    7
    
    • 1

    思路:
    最开始想到了分层图,但是没有想到虚拟源点。
    如果不用虚拟源点的话,就需要每层图的每个点之间相互连边,边数会很大,后来看了其他大佬的博客,发现针对不同层的同一个点,使用一个虚拟源点就可以解决这个问题。
    进入虚拟源点不需要花钱,但是从虚拟源点离开就需要花钱。
    在起点的时候,由于可以乘坐经过起点的任意一班地铁,故在本题中需要将起点设置为起点标号对应的虚拟源点。终点 同理。
    代码:

    #include
    #include
    #include
    using namespace std;
    typedef pair<int,int>PII;
    const int N=6e5+10,M=1e6+10;
    int n,m,s,t;
    int h[N], e[M], w[M],ne[M], idx;       // 邻接表
    bool st[N];     // 存储每个点是否在队列中
    int dist[N];
    void add(int a, int b, int c)
    {
        e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
    }
    
    int dijkstra(int s,int t)
    {
        memset(dist, 0x3f, sizeof dist);
        dist[s] = 0;
        priority_queue<PII, vector<PII>, greater<PII>> heap;
        heap.push({0, s});      // first存储距离,second存储节点编号
    
        while (heap.size())
        {
            auto t = heap.top();
            heap.pop();
    
            int ver = t.second, distance = t.first;
    
            if (st[ver]) continue;
            st[ver] = true;
    
            for (int i = h[ver]; i != -1; i = ne[i])
            {
                int j = e[i];
                if (dist[j] > distance + w[i])
                {
                    dist[j] = distance + w[i];
                    heap.push({dist[j], j});
                }
            }
        }
    
        if (dist[t] == 0x3f3f3f3f) return -1;
        return dist[t];
    }
    int main()
    {
        memset(h,-1,sizeof h);
        cin>>n>>m>>s>>t;
        for(int i=0;i<m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            int t;
            cin>>t;
            add(t+i*n,n*m+t,0);
            add(n*m+t,t+i*n,a);
            for(int j=0;j<c-1;j++)
            {
                int k;
                cin>>k;
                add(t+i*n,k+i*n,b);
                add(k+i*n,t+i*n,b);
                add(k+i*n,n*m+k,0);
                add(n*m+k,k+i*n,a);
                t=k;
            }
        }
        cout<<dijkstra(n*m+s,n*m+t);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
  • 相关阅读:
    C#餐饮收银系统
    实战:获取33种生活指数
    [蔚来杯]Two Frogs
    k8s资源管理操作——陈述式管理方式
    【我不熟悉的css】03. 使用px、em、rem
    会议OA系统
    mongo+ycsb性能测试及线程数分析
    基于Java毕业设计在线商城系统源码+系统+mysql+lw文档+部署软件
    1704. 判断字符串的两半是否相似 : 简单模拟题
    能源区块链实验室同俄罗斯碳基金签署重要战略合作协议
  • 原文地址:https://blog.csdn.net/weixin_50616227/article/details/126019335