Luogu P3110 [USACO14DEC]驮运Piggy Back

解题思路

看到下面很多人都在说什么遇到了之后要不要背着走,其实根本不需要,同样的我也是跑了三遍$SPFA$,求出了以$1$为起点到个点的$dist$,和以$2$为起点到个点的$dist$,还有以$n$为起点到个点的$dist$。

之后直接枚举两头牛在哪里相遇,相遇之后一起背着走的路程乘以$p+$相遇之前$B$走的距离乘以$b+$相遇之前$E$走的距离乘以$e$,去一个最小的这样的值就是答案。

关于为什么不需要分类讨论,因为你把每个点都枚举了一遍,即使存在$p>b+e$的情况,那这种情况就等价于两头奶牛在$n$点相遇。

 

附上代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
const int maxn = 8e4+3, INF = 2147483647;
int b, e, p, n, m, fir[maxn], nxt[maxn], u[maxn], v[maxn], cnt;
int dist_n[maxn], dist_1[maxn], dist_2[maxn], w[maxn], Ans = INF;
bool vis[maxn];
inline int read() {
    int x = 0, f = 1; char c;
    while (c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while (c <= '9' && c >= '0') {x = x*10 + c-'0'; c = getchar();}
    return x * f;
}
inline void addedge(int x, int y, int z) {
    nxt[++cnt] = fir[x];
    fir[x] = cnt;
    u[cnt] = x, v[cnt] = y, w[cnt] = z;
}
inline void SPFA(int s, int *dist) {
    std::queue<int> Q;
    std::memset(vis, 0, sizeof(vis));
    std::fill(dist+1, dist+1+n, INF);
    vis[s] = 1, dist[s] = 0;
    Q.push(s);
    int x, k;
    while (!Q.empty()) {
        x = Q.front(), Q.pop();
        int k = fir[x];
        while (k != -1) {
            if(dist[v[k]] > dist[u[k]] + w[k]) {
                dist[v[k]] = dist[u[k]] + w[k];
                if(!vis[v[k]]) Q.push(v[k]);
            }
            k = nxt[k];
        }
        vis[x] = 0;
    }
}
int main() {
    b = read(), e = read(), p = read(), n = read(), m = read();
    std::memset(fir, -1, sizeof(fir));
    int x, y, z = 1;
    for(register int i=1; i<=m; i++) {
        x = read(), y = read();
        addedge(x, y, z), addedge(y, x, z);
    }
    SPFA(1, dist_1), SPFA(2, dist_2), SPFA(n, dist_n);
    for(int i=1; i<=n; i++)
        Ans = std::min(Ans, dist_1[i] * b + dist_2[i] * e + dist_n[i] * p);
    printf("%d", Ans);
}

 

posted @ 2018-08-17 17:06  Mystical-W  阅读(274)  评论(0编辑  收藏  举报