POJ - 3268:Silver Cow Party

题目描述:

输入输出:

 思路:

读完题目,感觉这题简直是个小菜,不就是两个dijkstra嘛,简直有手就行,(事实证明,我就是一个废物。。。)

但是随着看题,看到题目中描述的f(i)是从x到i的最短路+从i到x的最短路,最后还要求max f(i)

我直接懵了,一个最短路和一个max值不就是相冲突的嘛,这出题人不是为难人嘛(***)

但是听了老师的讲解,渐渐懂了略微,在这里引用一下当时上课的例子给大家说明一下。

青岛->上海:青岛-济南-上海(去,6小时);上海-青岛(回,3小时)        共计9小时
青岛->烟台:青岛-烟台(去,2小时);烟台-青岛(回来,2小时)             共计4小时
青岛->青海:青岛-青海(去,6小时);青海-青岛(回,6小时)                共计12小时

给定四个城市,分别是青岛、上海、烟台、青海。给定你一个城市x,设f(i)为从i这个城市到x这个城市的最短路,加上从x这个城市到i这个城市的最短路,求f(i)最大值。
现在x就是青岛。i可以是上海,烟台,青海
f(上海)=9
f(yt)=4
f(qh)=12

max{f} = max(f(sh), f(yt), f(qh)) = 12

//这简直就是强迫症的福音啊qwq

想必看到这,大家心里可能有了一丝见解,我在详细的说一下;

何所谓找到最短路的max值呢,这里再给大家举个例子:

假设此题的x视为5;

剩余的四个点分别为1,2,3,4。其中1->2,1->3,3->4,2->5,4->5,我呢就要通过利用刚才信息所构成的图中找出1,2,3,4四个点每个点到达5点的最短路径,在将他们的和分别相加起来,最后在相加完成的4个和中选取一个max值。

//这么看来,最短路和max值原来是不冲突的啊,可怜当时的我想秃了头,结果用了一个无比笨拙的没用优化的纯松弛操作来完成此题。            

 那么这题想到这基本就没有啥难点了,利用一个反向建边进行dijkstra就好啦。其中有许多小技巧咱们代码里见。

#include <cstring>
#include <cmath>
#include <iostream>
#include <queue>
#include <map>
#include <vector>

const int N = 100005;

struct EDGE {
    int v, w, next;
} e[2][N << 1];

int head[2][N], tot[2] = {1, 1};//为啥要建立二维数组呢?是不是很新奇
//因为正反向建边是完全不同的,要两次来记录,用二维数组较为方便,简洁。
void add(int u, int v, int w, int opt) {//因为反向建边说明我们要建两次
    e[opt][tot[opt]].v = v;//opt就是记录我们是正向建边,还是反向建边
    e[opt][tot[opt]].w = w;
    e[opt][tot[opt]].next = head[opt][u];
    head[opt][u] = tot[opt] ++;
}

struct Node {
    int pos, dis;
    
    Node() {};

    Node(int pos, int dis): pos(pos), dis(dis) {};

    bool operator < (const Node &x) const {
        return dis > x.dis;
    }
};

int dis[2][N], vis[N];

void dijkstra(int opt, int s) {
    std::priority_queue<Node> q;
    memset(dis[opt], 0x3f, sizeof dis[opt]);
    memset(vis, 0, sizeof vis);
    dis[opt][s] = 0;
    q.push(Node(s, 0));
    while (!q.empty()) {//比普通的dijkstra就多了一个opt,就多了一个两种方向的建边而已
        Node f = q.top();
        q.pop();
        int u = f.pos;
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[opt][u]; i; i = e[opt][i].next) {
            int v = e[opt][i].v;
            int w = e[opt][i].w;
            if (!vis[v] && dis[opt][v] > dis[opt][u] + w) {
                dis[opt][v] = dis[opt][u] + w;
                q.push(Node(v, dis[opt][v]));
            }
        }
    }
}

int main() {
    // freopen("/Users/chant/in.txt", "r", stdin);
    int n, m, x;
    std::cin >> n >> m >> x;
    for (int i = 0; i < m; i++) {
        int u, v, w;
        std::cin >> u >> v >> w;
        add(u, v, w, 0);
        add(v, u, w, 1);
    }
    dijkstra(0, x);
    dijkstra(1, x);
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        ans = std::max(ans, dis[0][i] + dis[1][i]);
    }
    std::cout << ans << '\n';
    return 0;
}

总结:本题的难点就是之前列举的最小值&max值,还有正反向建边的opt巧妙运用,这个题出的比较的巧妙,思路和代码难度都还是比较大的,并不算难,但是最优解的方法比较的奇葩。

创作不易,请勿白嫖啊www!麻烦给作者三连+关注一下啦!谢!

猜你喜欢

转载自blog.csdn.net/2301_76331300/article/details/131597942