Codeforces 938D. Buy a Ticket (最短路+建图)

<题目链接>

题目大意:

有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\n",node[i].dist):printf("%lld ",node[i].dist);
}

 

posted @ 2019-04-11 12:27  悠悠呦~  阅读(358)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end