赛艇表演 51nod提高组模拟试题
题目描述
小明去某个地区观看赛艇比赛,这个地区共有n个城市和m条道路,每个城市都有赛艇比赛,在第i个 城市观看赛艇表演的价钱为ai, 去其他城市观看也需要支付赛艇表演的价格。任意两个城市之间通过 一条公路连接,并且道路是双向通行的, 观看赛艇比赛时经过的每一条道路都要支付一定的过路费, 观看完比赛返回家时经过的每一条道路也要支付过路费。 对于每个城市u,你需要为小明确定一个城市v,使得从u出发,前往v看赛艇表演,再从v回到u,u可 以等于v,要求花费的总金额尽量的少。请根据题目给出的数据输出总金额。
输入格式
第一行两个正整数n和m。 接下来m行,每行三个正整数u,v,w,表示有一条双向道路连接u和v,且每经过一次的过路费是 w。 接下来一行n个数,第i个数表示在第i个城市观看赛艇表演的价钱。
输出格式
输出一行n个数,第i个数表示从第i个城市出发至少要花多少钱
数据范围
对于前30%的数据,n<=10,m<=20。 对于前50%的数据,n<=100,m<=500。 对于前70%的数据,n<=1500,m<=2000。 对于前85%的数据,图的结构以某种方式随机生成。 对于100%的数据,n<=2e5,m<=2e5,过路费和门票钱都在[1,1e12]内。
输入样例
4 2
1 2 4
2 3 7
6 20 1 25
输出样例
6 14 1 25
一道十分有趣的题。首先的思路肯定是对于每个城市,枚举终点,并求出其对应的最短路。
然而,毫无疑问,这样的结果便是一片TLE。
这道题最棘手的一点,便是每个点本身的price 和 路径的w均会对结果造成影响。
而这也导致我们不能直接使用最短路算法求出路径w最小。
考虑一种方法,使得price和w可以同时被考虑。
而且原题已经明确的给出了我们一张图,也要尽量利用这张图。
想出一种建图方法:
设立一个超级源点S,将其和所有的点之间连边,大小为price,然后从其跑最短路。最短路得到的dis即为每个点的答案。
而点与点之间的路径,完全可以直接设为2w,不用真的跑来回。这样,我们就直接考虑了price和w。
可以看一下对应操作: 对于下图三号点,从s直接到3即为在原地观看,从s -> 1 -> 3即为从3点去1点观看。
(惊叹,斜视,默坐,以为绝妙)
千少万少,代码不能少
#include<bits/stdc++.h> using namespace std; #define N 100010 #define ll long long inline ll read(){ ll x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-')s = -1; c = getchar(); } while(isdigit(c)){ x = (x << 1) + (x << 3) + (c ^ '0'); c = getchar(); } return x * s; } ll n, m; struct hehe{ ll u, v, w; ll next; }t[N]; ll f[N]; struct node{ ll now, dis; bool operator < (const node& a) const{ return dis > a.dis; } }; ll d[N]; bool vis[N]; priority_queue <node> q; ll bian = 0; inline void add(ll u, ll v, ll w){ t[++bian].u = u; t[bian].v = v; t[bian].w = w; t[bian].next = f[u]; f[u] = bian; return ; } void dijstra(ll s){ memset(d, 127, sizeof(d)); q.push((node){s,0}); d[s] = 0; while(!q.empty()){ node temp = q.top(); q.pop(); ll now = temp.now, dis = temp.dis; if(!vis[now]){ vis[now] = 1; for(int i = f[now];i;i = t[i].next){ ll v = t[i].v, w = t[i].w, u = t[i].u; if(d[v] > d[u] + w){ d[v] = d[u] + w; if(!vis[v]) q.push((node) {v, d[v]}); } } } } return ; } int main(){ n = read(), m = read(); for(int i = 1;i <= m; i++){ ll x = read(), y = read(), w = read(); add(x, y, w << 1);add(y, x, w << 1); } for(int i = 1;i <= n; i++){ ll x = read(); add(0, i, x); add(i, 0, x); } dijstra(0); for(int i = 1;i <= n; i++) printf("%d ",d[i]); return 0; }