CF 938D Buy a Ticket - 最短路
CF 938D Buy a Ticket
算法标签: 最短路
、图论
题目
题目描述
流行乐队“Flayer”将在n个城市开演唱会 这n个城市的人都想去听演唱会 每个城市的票价不同 于是这些人就想是否能去其他城市听演唱会更便宜(去要路费的) 输入格式: 第一行包含两个整数n和m 接下来m行 每行三个数 u v k 表示u城市到v城市要k元 接下来n个数 表每个城市的票价
输入格式
The first line contains two integers \(n\) and \(m\) \(( 2<=n<=2·10^{5} , 1<=m<=2·10^{5} )\).
Then \(m\) lines follow,$ i $-th contains three integers \(v_{i}\) , \(u_{i}\) , and \(w_{i}\) \(( 1<=v_{i},u_{i}<=n,v_{i}≠u_{i} , 1<=w_{i}<=10^{12} )\) denoting \(i\) -th train route. There are no multiple train routes connecting the same pair of cities, that is, for each \((v,u)\)neither extra$ (v,u)$ nor$ (u,v) $present in input.
The next line contains nn integers \(a_{1},a_{2},...\ a_{k} ( 1<=a_{i}<=10^{12} )\) — price to attend the concert in \(i\)-th city.
输出格式
Print \(n\) integers. \(i\) -th of them must be equal to the minimum number of coins a person from city $ i$ has to spend to travel to some city $ j$ (or possibly stay in city $ i $), attend a concert there, and return to city \(i (if~~ j≠i )\).
输入输出样例
输入 #1
4 2
1 2 4
2 3 7
6 20 1 25
输出 #1
6 14 1 25
输入 #2
3 3
1 2 1
2 3 1
1 3 1
30 10 20
输出 #2
12 10 12
题解:
最短路+超级源点
为什么在考场上想了那么久 ———— 《打脸》
这种描述很轻松就可以看出来这是一道略微不太正经的最短路,不正经在哪???
- 开完演唱会还需要回到原来的城市——二倍边权
- 在每个点开演唱会有一定的点权——\(Important\)
二倍边权这个怎么处理不用说了吧………………
问题就在于如何处理点权??每个点都跑一下Dij??
——显然做不到
考虑超级源点,把所有点都与超级源点连接一条边权为该点点权的边,对于超级源点跑最短路。(除了超级源点与每个点之间的边以外的所有边都要存二倍边权)。
这样跑完直接就是结果了。
AC代码
#include <bits/stdc++.h>
#define setI(x) freopen(x".in", "r", stdin);
#define setO(x) freopen(x".out", "w", stdout);
#define setIO(x) setI(x) setO(x)
using namespace std;
typedef long long ll;
char *p1, *p2, buf[100000];
#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )
int rd() {
int x = 0, f = 1;
char c = nc();
while (c < 48) {
if (c == '-') {
f = -1;
}
c = nc();
}
while (c > 47) {
x = (((x << 2) + x) << 1) + (c ^ 48);
c = nc();
}
return x * f;
}
ll lrd() {
ll x = 0, f = 1;
char c = nc();
while (c < 48) {
if (c == '-') {
f = -1;
}
c = nc();
}
while (c > 47) {
x = (((x << 2) + x) << 1) + (c ^ 48);
c = nc();
}
return x * f;
}
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
int tot, head[N], to[N << 2], nxt[N << 2];
ll val[N << 2];
int n, m;
ll num[N];
ll dis[N];
bool vis[N];
void add(int x, int y, ll z) {
to[ ++ tot] = y;
val[tot] = z;
nxt[tot] = head[x];
head[x] = tot;
}
priority_queue < pair<ll, int> > q;
void dijkstra(int s)
{
memset(dis, 0x3f, sizeof dis);
// memset(vis, 0, sizeof vis);
dis[s] = 0;
q.push(make_pair(0, s));
while (!q.empty())
{
if (vis[q.top().second])
{
q.pop();
continue ;
}
int x = q.top().second;
q.pop();
vis[x] = 1;
for (int i = head[x]; i; i = nxt[i])
{
if (dis[to[i]] > dis[x] + val[i])
{
dis[to[i]] = dis[x] + val[i];
q.push(make_pair(-dis[to[i]], to[i]));
}
}
}
}
int main() {
// setIO("movie");
// scanf("%d%d", &n, &m);
n = rd(), m =rd();
for (int i = 1; i <= m; i ++ ) {
int a = rd(), b = rd();
ll c = lrd();
add(a, b, c * 2);
add(b, a, c * 2);
}
for (int i = 1; i <= n; i ++ ) {
num[i] = lrd();
add(0, i, num[i]);
}
dijkstra(0);
for (int i = 1; i <= n; i ++ ) {
printf("%lld ", dis[i]);
}
return 0;
}