洛谷P2984《[USACO10FEB]给巧克力Chocolate Giving》

原更新日期:2019-01-10 22:06:13

此时一位单身🐂路过

题目描述

Farmer John有B头奶牛\((1<=B<=25000)\),有\(N(2*B<=N<=50000)\)个农场,编号\(1\rightarrow N\),有\(M(N-1<=M<=100000)\)条双向边,第\(i\)条边连接农场\(R_i\)\(S_i(1<=R_i<=N;1<=S_i<=N)\),该边的长度是\(L_i(1<=L_i<=2000)\)。居住在农场\(P_i\)的奶牛\(A(1<=P_i<=N)\),它想送一份新年礼物给居住在农场\(Q_i(1<=Q_i<=N)\)的奶牛\(B\),但是奶牛\(A\)必须先到FJ(居住在编号\(1\)的农场)那里取礼物,然后再送给奶牛\(B\)。你的任务是:奶牛\(A\)至少需要走多远的路程?

输入输出格式

输入格式

第一行:三个用空格隔开的整数\(N\),\(M\)\(B\)

第二到\(M+1\)行:第\(i+1\)行用\(R_i\)\(S_i\)\(L_i\)三个用空格隔开的整数描述双向边\(i\)

\(M+2\)\(M+B+1\)行:第\(M+i+1\)行包含两个用空格隔开的整数\(P_i\)\(Q_i\)

输出格式

第一到\(B\)行:第\(i\)行包括一个整数,居住在农场\(P_i\)的公牛从FJ那里取得情人节巧克力后送给他居住在农场\(Q_i\)的梦中情牛至少需要走的距离。

输入输出样例

输入样例

6 7 3 
1 2 3 
5 4 3 
3 1 1 
6 1 9 
3 4 2 
1 4 4 
3 2 2 
2 4 
5 1 
3 6 

输出样例

6
6
10

解题思路

这道题就是给你一张图和多个询问,对于每个询问,求两个点到点\(1\)的最短路径之和。

由于双向边的最短路可逆,我们可以得出下面的结论:

对于两条边\((i,j)\)\((j,i)\),有

\(dis_{(i,j)} = dis_{(j,i)}\)

所以我们只需要预处理出点\(1\)到其他所有点的最短路,然后对于每个询问\(P,Q\)输出 \(dis_{(1,P)} + dis_{(1,Q)}\) 即可

代码实现

/* -- Basic Headers -- */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>

/* -- STL Iterators -- */
#include <vector>
#include <string>
#include <stack>
#include <queue>

/* -- External Headers -- */
#include <map>
#include <cmath>

/* -- Defined Functions -- */
#define For(a,x,y) for (int a = x; a <= y; ++a)
#define Forw(a,x,y) for (int a = x; a < y; ++a)
#define Bak(a,y,x) for (int a = y; a >= x; --a)

namespace FastIO {
    
    inline int getint() {
        int s = 0, x = 1;
        char ch = getchar();
        while (!isdigit(ch)) {
            if (ch == '-') x = -1;
            ch = getchar();
        }
        while (isdigit(ch)) {
            s = s * 10 + ch - '0';
            ch = getchar();
        }
        return s * x;
    }
    inline void __basic_putint(int x) {
        if (x < 0) {
            x = -x;
            putchar('-');
        }
        if (x >= 10) __basic_putint(x / 10);
        putchar(x % 10 + '0');
    }
    
    inline void putint(int x, char external) {
        __basic_putint(x);
        putchar(external);
    }
}


namespace Solution {
    const int MAXN = 50000 + 10;
    const int MAXM = 100000 + 10;
    
    struct Node {
        int now, weight;
        
        Node() { now = weight = 0; }
        Node(int now, int weight) : now(now), weight(weight) {}
        
        bool operator < (const Node &that) const {
            return weight > that.weight;
        }
    };
    
    Node NewNode(int now, int weight) {
        Node tmp;
        tmp.now = now;
        tmp.weight = weight;
        return tmp;
    }
    
    struct Edge {
        int now, next, weight;
    } edge[MAXM * 2];
    
    int n, m, b, cnt, head[MAXN], dis[MAXN];
    
    inline void addEdge(int prev, int next, int weight) {
        edge[++cnt].now = next;
        edge[cnt].weight = weight;
        edge[cnt].next = head[prev];
        head[prev] = cnt;
    }
    
    inline void SFPA(int s) {
    	// 要注意的是
    	// 据说这题不卡 SPFA
    	// 但为保险起见
    	// 我还是选择 Dijkstra
        memset(dis, 0x7f7f7f7f, sizeof dis);
        dis[s] = 0;
        std::priority_queue<Node> q;
        q.push(NewNode(s, 0));
        while (!q.empty()) {
            Node NowNode = q.top();
            q.pop();
            int nownode = NowNode.now;
            for (int e = head[nownode]; e; e = edge[e].next) {
                int now = edge[e].now;
                if (dis[now] > dis[nownode] + edge[e].weight) {
                    dis[now] = dis[nownode] + edge[e].weight;
                    q.push(NewNode(now, dis[now]));
                }
            }
        }
    }
}

signed main() {
#define HANDWER_FILE
#ifndef HANDWER_FILE
    freopen("testdata.in", "r", stdin);
    freopen("testdata.out", "w", stdout);
#endif
    using namespace Solution;
    using FastIO::getint;
    n = getint();
    m = getint();
    b = getint();
    For (i, 1, m) {
        int prev = getint();
        int next = getint();
        int weight = getint();
        addEdge(prev, next, weight);
        addEdge(next, prev, weight);
    }
    SFPA(1);
    // 预处理出最短路
    For (i, 1, b) {
        int a = getint();
        int b = getint();
        int ans = dis[a] + dis[b];
        // 转化过的问题的答案,也是最终答案
        FastIO::putint(ans, '\n');
    }
    return 0;
}


posted @ 2020-10-14 18:22  Handwer  阅读(45)  评论(0编辑  收藏  举报