【题解】 [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;
}
posted @ 2024-08-12 20:57  T_泓  阅读(26)  评论(0编辑  收藏  举报