赛艇表演

问题 A: 赛艇表演

题目描述

小明去某个地区观看赛艇比赛,这个地区共有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个城市出发至少要花多少钱

样例输入

4 2
1 2 4
2 3 7
6 20 1 25

样例输出

6 14 1 25

提示

对于前30%的数据,n<=10,m<=20。 
对于前50%的数据,n<=100,m<=500。 
对于前70%的数据,n<=1500,m<=2000。 
对于前85%的数据,图的结构以某种方式随机生成。 
对于100%的数据,n<=2e5,m<=2e5,过路费和门票钱都在[1,1e12]内。
 
题解
   
  一道有意思的题目,一个好点子。
  最简单的想法就是暴力枚举每个点,然后spfa,这样无疑会超时。所以怎么解决超时的问题?建一个超级源点,从源点到其他每个点的距离就是观看表演的费用,因为看完表演还要回去,所以其他两点建边时直接按照两倍边权建边,然后从源点开始跑一遍spfa就可以了。只需一遍spfa!!!
 
 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 typedef long long LL;
 7 typedef pair<int,LL> PIR;
 8 const int N=202020;
 9 int n,m,k;
10 LL g[N],dis[4*N];
11 int fir[N],poi[4*N],nex[4*N];
12 bool f[N];
13 PIR d[N];
14 queue<int>q;
15 void add(int x,int y,LL z)
16 {
17     nex[++k]=fir[x];
18     fir[x]=k;
19     poi[k]=y;
20     dis[k]=z;
21 }
22 void spfa(int x)
23 {
24     d[x].second=0;
25     for(int i=fir[x];i;i=nex[i])
26         d[poi[i]].first=poi[i],
27         d[poi[i]].second=dis[i],
28         q.push(poi[i]),
29         f[poi[i]]=1;
30     while(!q.empty())
31     {
32         int now=q.front();
33         f[now]=0;
34         q.pop();
35         for(int i=fir[now];i;i=nex[i])
36             if(d[now].second+dis[i]<d[poi[i]].second)
37             {
38                 d[poi[i]].second=d[now].second+dis[i];
39                 d[poi[i]].first=d[now].first;
40                 if(!f[poi[i]])
41                 {
42                     q.push(poi[i]);
43                     f[poi[i]]=1;
44                 }
45             }
46     }
47 }
48 int main()
49 {
50     scanf("%d%d",&n,&m);
51     for(int i=1;i<=m;i++)
52     {
53         int x,y;
54         LL z;
55         scanf("%d%d%lld",&x,&y,&z);
56         add(x,y,z*2);
57         add(y,x,z*2);
58     }
59     memset(d,0x3f,sizeof(d));
60     for(int i=1;i<=n;i++)
61         scanf("%lld",&g[i]),
62         add(0,i,g[i]),
63         add(i,0,g[i]);
64     spfa(0);
65     for(int i=1;i<=n;i++)
66         printf("%lld ",d[i].second);
67     printf("\n");
68     return 0;
69 }
View Code

 

posted @ 2019-11-12 22:12  Johnny-English  阅读(234)  评论(0编辑  收藏  举报