赛艇表演 51nod提高组模拟试题

Posted wondering-world

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了赛艇表演 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;
}

 

 

 

 

 

以上是关于赛艇表演 51nod提高组模拟试题的主要内容,如果未能解决你的问题,请参考以下文章

小智的旅行(Bridge)51nod 提高组试题

小智的糖果(Candy) 51nod 提高组试题

51Nod 1082 | 模拟

51Nod 1289 大鱼吃小鱼 栈的简单模拟

51nod 1515 明辨是非 [并查集+set]

题解51 nod 1049