L2-2 不要***难我们了
分数 25
作者 rea_lity
单位 成都信息工程大学
题目描述:
ShallowMaple 和 YFffffff 发现今年的算法题目过于的 ***难 我们的算法选手,于是他们两个想打电话来通知 rea_lity 修改题目的难度。要对我们的 蒜金(算法竞赛) 选手更加的友好。众所周知,电话信号要被传输到由基站建成的网络,而网络的传输需要一定的时间。当然,基站内部处理数据也需要一定的时间。
当 rea_lity 接到这个消息的时候,思考到一个问题:
- 每一个基站都有一个独有的ID(1∼n)。
- rea_lity 现在知道基站 a 和基站 b 之间传输信息需要时间 t ,并且信息可以双向传输(即,a 可以向 b 发送信息,b 也可以向 a 发送信息)。
- rea_lity 也知道 ID 为 i 的基站内部处理数据所需要的时间为 Ti,并且只有接收端基站才会消耗时间。
- ShallowMaple 和 YFffffff 所处于的基站的 ID 为 start ,rea_lity 所处的基站的 ID 为 end 。
- 一个基站不会向自己传输信息,两个基站之间可能会有多条传输路径。
问题为,ShallowMaple 和 YFffffff 打电话过来所消耗的时间 最短 是多少,又有多少种不同的 最短 时间路径呢?
输入描述:
- 第一行有两个数字 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(){ //dijsktramemset(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];}