欢迎来到我的算法与代码笔记(建设中)

在这里记录学习之旅,分享编程心得,用二次元的活力激发灵感!

开始阅读

随笔标题一

简要摘要介绍,方便读者快速了解文章主要内容。

随笔标题二

简要摘要介绍,方便读者快速了解文章主要内容。

不要为难我们了(最短路,djs)

L2-2 不要***难我们了

分数 25

作者 rea_lity

单位 成都信息工程大学

题目描述:

ShallowMapleYFffffff 发现今年的算法题目过于的 ***难 我们的算法选手,于是他们两个想打电话来通知 rea_lity 修改题目的难度。要对我们的 蒜金(算法竞赛) 选手更加的友好。众所周知,电话信号要被传输到由基站建成的网络,而网络的传输需要一定的时间。当然,基站内部处理数据也需要一定的时间。

rea_lity 接到这个消息的时候,思考到一个问题:

  • 每一个基站都有一个独有的ID(1∼n)。
  • rea_lity 现在知道基站 a 和基站 b 之间传输信息需要时间 t ,并且信息可以双向传输(即,a 可以向 b 发送信息,b 也可以向 a 发送信息)。
  • rea_lity 也知道 ID 为 i 的基站内部处理数据所需要的时间为 Ti​,并且只有接收端基站才会消耗时间。
  • ShallowMapleYFffffff 所处于的基站的 ID 为 start ,rea_lity 所处的基站的 ID 为 end 。
  • 一个基站不会向自己传输信息,两个基站之间可能会有多条传输路径。

问题为,ShallowMapleYFffffff 打电话过来所消耗的时间 最短 是多少,又有多少种不同的 最短 时间路径呢?

输入描述:

  • 第一行有两个数字 n ,m(1⩽n⩽2×105,1⩽m⩽2×105) ,在这个网络中有 n 个基站,和 m 条传输线路。
  • 第二行有两个数字 start,end ,表示开始和结束位置的基站 ID(1⩽ID⩽n)。
  • 第三行有 n 个数,Ti​(1⩽i⩽n,0<Ti​⩽105) 表示第 i 个基站内部处理数据的时间。
  • 接下来的 m 行,每一行有三个数字 a,b,t,表示 a 和 b 之间传输信息需要时间 t(0<t⩽105) 。

输出描述:

  • 第一行输出一个数字,表示 start 到 end 所需最短时间。
  • 第二行输出一个数字,表示最短时间的路径有多少条。

输入样例:

4 51 41 2 3 11 2 10001 2 12 3 13 4 11 4 8

输出样例:

92

样例解释:

  • 有两种路线花费的时间最短为 9 ,第一条为 (1→2→3→4),第二条为 (1→4)

分析

明显最短路问题,使用链式前向星存边,再用Dijkstra算法求最短路,用队列优先优化时间为\((mlogm)\)

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 4e5+5;  //注意双向边!!!!!!!!!!!!!!!!所以应该有4e5
int head[N],idx;      
struct edge{          //边
    int to, w, nxt;
    edge(){}
    edge(int to, int w, int nxt):to(to), w(w), nxt(nxt){}
};

bool vis[N];        //标记
int dis[N];        //距离数组

struct Node            //节点
{
    int pos, dis;
    Node(){}
    Node(int pos, int dis):pos(pos), dis(dis){}
    bool operator < (const Node& a) const{
        return dis > a.dis;
    }
    /* data */
};

priority_queue<Node> q;    //队里优先
int n, m , sta, ed;

edge e[N];                                

inline void add(int u, int to, int w){   
    e[++idx] = {to, w, head[u]};
    head[u] = idx;
}

int ways[N], wig[N];         

void djs(){               //dijsktra
    memset(dis, 0x3f, sizeof(dis));  //距离初始化大
    dis[sta] = 0;
    ways[sta] = 1;
    q.push({sta, 0});
    
    while(!q.empty()){
        Node t = q.top();
        q.pop();
        int pos = t.pos;
        if(vis[pos]) continue;     //如果已经进出过队了,就不会再成为最短节点
        vis[pos] = true;           //标记已经成为了最短的节点

        for(int i = head[pos];i ; i = e[i].nxt){  //遍历
            int to = e[i].to;                               
            if(!vis[to] && dis[pos]+e[i].w < dis[to]){  //没有成为过最短节点,进行松弛操作
                dis[to] = dis[pos] + e[i].w;       
                ways[to] = ways[pos];
                q.push({to, dis[to]});                  //最短节点候选
            }
            else if (dis[to] == dis[pos]+e[i].w){       //距离相等,路径数相加
                ways[to] += ways[pos];
            }
            
        }
    }
    
}

int main(){
    cin >> n >> m >> sta >> ed;
    for(int i = 1;i <= n; ++i) cin >> wig[i];

    for(int i = 1;i <= m; ++i){
        int a, b, t;
        cin >> a >> b >> t;
        add(a, b, t+wig[b]);
        add(b, a, t+wig[a]);      //双向边
    }
    djs();
    cout << dis[ed] << '\n' << ways[ed];
    
}
posted @ 2025-03-22 12:28  bakul  阅读(9)  评论(0)    收藏  举报