【题解】 [USACO 2007 FEB] Cow Party S
题目描述
题目大意
给定一个有向图,以及一个顶点。求其他所有点到给定点,再从给定点回到各自起始点的最短路中的最大值。
思路
本题主要考查:对单源最短路算法的熟练运用。
最短路总共分为2段:其他所有点到给定点、给定点回到各自起始点。
首先求第一段:可以在原图的基础上建一个反向图,再以给定点为起点跑一遍Dijkstra。
然后求第二段:直接在原图上,也是以给定点为起点跑一遍Dijkstra。
最后再将两遍Dijkstra的答案相加,取最大值即可。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 1e5 + 5;
int n, m, x;
int u[M], v[M], w[M];
int sum[N];
// 链式前向星 存图
int head[N], idx;
struct Edge
{
int next, to, val;
}edge[M];
void add(int u, int v, int w)
{
edge[idx].to = v, edge[idx].val = w;
edge[idx].next = head[u];
head[u] = idx ++ ;
}
void init()
{
memset(head, -1, sizeof head);
}
// Dijkstra 模版
int dis[N];
bool vis[N];
void Dijkstra(int st)
{
memset(dis, 0x3f, sizeof dis);
memset(vis, false, sizeof vis);
dis[st] = 0;
for (int i = 1; i < n; i ++ )
{
int u = -1;
for (int j = 1; j <= n; j ++ )
if (!vis[j] && (u == -1 || dis[j] < dis[u]))
u = j;
vis[u] = true;
for (int j = head[u]; ~j; j = edge[j].next )
{
int v = edge[j].to, w = edge[j].val;
dis[v] = min(dis[v], dis[u] + w);
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &x);
init();
for (int i = 1; i <= m; i ++ )
{
scanf("%d%d%d", &u[i], &v[i], &w[i]);
add(v[i], u[i], w[i]); // 建反向图
}
Dijkstra(x);
for (int i = 1; i <= n; i ++ ) sum[i] = dis[i]; // 保存答案
init();
for (int i = 1; i <= m; i ++ ) add(u[i], v[i], w[i]); // 建正向图
Dijkstra(x);
for (int i = 1; i <= n; i ++ ) sum[i] += dis[i]; // 将答案相加
// 取最大值
int ans = -0x3f3f3f3f;
for (int i = 1; i <= n; i ++ )
ans = max(ans, sum[i]);
printf("%d\n", ans);
return 0;
}