题目链接:POJ 3268
Description
Input
Output
Sample Input
4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3
Sample Output
10
Hint
Source
Solution
题意
给定 \(n\) 个点和 \(m\) 条边的有向图,每个点有一头牛,牛 \(a\) 到牛 \(b\) 需花费的时间为 \(t\),现在所有的牛要到牛 \(x\) 所在的点去,求所有牛去牛 \(x\) 处再返回的最短时间中的最大值。
思路
Dijkstra
对原图和反向建边的图各跑一次 \(Dijkstra\),两次的 \(d\) 数组的和就是每头牛的往返的最短时间,然后找出其中的最大值即可。
Code
#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <functional>
using namespace std;
const int N = 1010, M = 1e5 + 10;
const int inf = 0x3f3f3f3f;
typedef pair<int, int> P;
int n, m, x;
int s[M], e[M], w[M];
struct Edge {
int to, w;
Edge(int to, int w): to(to), w(w) {}
};
vector<Edge> G[N];
int d[N], vis[N];
int cnt[N];
void init() {
for(int i = 0; i < N; ++i) {
G[i].clear();
}
}
void add(int x, int y, int z) {
G[x].push_back(Edge(y, z));
}
void dijkstra(int s) {
priority_queue<P,vector<P>,greater<P> > q;
memset(d, 0x3f, sizeof(d));
memset(vis, 0, sizeof(vis));
d[s] = 0;
q.push(P(0, s));
while(q.size()) {
P p = q.top(); q.pop();
int x = p.second;
if(vis[x]) continue;
vis[x] = 1;
for(int i = 0; i < G[x].size(); ++i) {
Edge e = G[x][i];
if (d[e.to] > d[x] + e.w) {
d[e.to] = d[x] + e.w;
q.push(P(d[e.to], e.to));
}
}
}
}
int main() {
init();
scanf("%d%d%d", &n, &m, &x);
for(int i = 1; i <= m; ++i) {
scanf("%d%d%d", &s[i], &e[i], &w[i]);
add(s[i], e[i], w[i]);
}
dijkstra(x);
for(int i = 1; i <= n; ++i) {
cnt[i] = d[i];
}
init();
for(int i = 1; i <= m; ++i) {
add(e[i], s[i], w[i]);
}
dijkstra(x);
int ans = 0;
for(int i = 1; i <= n; ++i) {
ans = max(ans, cnt[i] + d[i]);
}
printf("%d\n", ans);
return 0;
}