CF 938D Buy a Ticket - 最短路

CF 938D Buy a Ticket

题目链接:洛谷 CF938D 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;

}
posted @ 2019-11-12 21:55  筱柒_Littleseven  阅读(116)  评论(0编辑  收藏  举报