题目描述:
输入输出:
思路:
读完题目,感觉这题简直是个小菜,不就是两个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)=12max{f} = max(f(sh), f(yt), f(qh)) = 12
//这简直就是强迫症的福音啊qwq
想必看到这,大家心里可能有了一丝见解,我在详细的说一下;
何所谓找到最短路的max值呢,这里再给大家举个例子:
扫描二维码关注公众号,回复: 16356297 查看本文章假设此题的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!麻烦给作者三连+关注一下啦!谢!