<题目链接>
题目大意:
有n座城市,每一个城市都有一个听演唱会的价格,这n座城市由m条无向边连接,每天变都有其对应的边权。现在要求出每个城市的人,看一场演唱会的最小价值(总共花费的价值=所看演唱会的价值+该城市的人去那个城市看演唱会的往返距离之和)。
解题分析:
比较好的一道最短路题,主要考察建图能力。我们不妨建立一个虚拟源点,然后该源点向所有的边都连上一条无向边,边权为对应点的点权。然后所有的点之间通过m条边连接,只不过边权设为2倍原边权。最后就是从源点跑一遍最短路,就能得到每个城市的人能够看演唱会的最小价值。这里有点逆向思维的意思,源点向所有点连一条边权为$a[i]$的边,代表该点作为最后看演唱会的城市,所贡献的价值。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+5 ; const ll INF = 1e18; template<typename T> inline void read(T&x){ x=0;int f=1;char c=getchar(); while(c<'0' || c>'9'){ if(c=='-')f=-1;c=getchar(); } while(c>='0' && c<='9'){ x=x*10+c-'0';c=getchar(); } x*=f; } struct Edge{ int from,to,nxt;ll val; }e[N<<2]; int n,m,cnt; int head[N],vis[N]; struct Node{ int loc;ll dist; bool operator < (const Node &tmp)const{ return dist>tmp.dist; } }node[N]; inline void add(int u,int v,ll w){ e[++cnt]=(Edge){u,v,head[u],w}; head[u]=cnt; } inline void Dij(int st){ for(int i=0;i<=n;i++){ vis[i]=0,node[i]=(Node){i,INF}; } priority_queue<Node>q; node[0].dist=0; q.push(node[0]); while(q.size()){ int u=q.top().loc;q.pop(); if(vis[u])continue; vis[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to;ll cost=e[i].val; if(node[v].dist>node[u].dist+cost){ node[v].dist=node[u].dist+cost; q.push(node[v]); } } } } int main(){ read(n);read(m); for(int i=1;i<=m;i++){ int u,v;ll w; read(u);read(v);read(w); add(u,v,2*w);add(v,u,2*w); } for(int i=1;i<=n;i++){ ll val;read(val); add(0,i,val);add(i,0,val); } Dij(0); for(int i=1;i<=n;i++) i==n?printf("%lld ",node[i].dist):printf("%lld ",node[i].dist); }