农场派对

https://loj.ac/problem/10075

题目描述

  给出n个节点和m条有向边,求从每个节点到x往返的最短路径中的最大值。

思路

  由于正着思考我们虽然只能一次求出x到其他各点,但每次要求出i到x的最短路,显然会T掉。我们考虑建原图的反图,那么i到x的最短路可以转化为再反图上x到i的最短路,因为边权不变,最短路径经过的节点是相同。进行两遍Dijkstra即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int MAXM=100005,MAXN=1005;
struct aa
{
    int nxt,to,w;
}e[MAXM][2];
int head[MAXN][2],tot[2],dis[MAXN][2],x;
bool used[MAXN][2];
void add_edge(int x,int y,int v,int f)
{
    e[++tot[f]][f].nxt=head[x][f];
    head[x][f]=tot[f];
    e[tot[f]][f].to=y;
    e[tot[f]][f].w=v;
}
void Dijkstra(int f)
{
    priority_queue<pair<int,int> >q;
    dis[x][f]=0;q.push(make_pair(0,x));
    while(!q.empty())
    {
        int u=q.top().second;q.pop();
        if(used[u][f])continue ;
        used[u][f]=1;
        for(int i=head[u][f];i;i=e[i][f].nxt)
        {
            int v=e[i][f].to;
            if(dis[v][f]>dis[u][f]+e[i][f].w)
            {
                dis[v][f]=dis[u][f]+e[i][f].w;
                q.push(make_pair(-dis[v][f],v));
            }
        }
    }
}
int main() 
{
    memset(dis,0x3f,sizeof(dis));
    int n,m;
    scanf("%d%d%d",&n,&m,&x);
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add_edge(a,b,c,0);
        add_edge(b,a,c,1);
    }
    Dijkstra(0);Dijkstra(1);
    int ans=0;
    for(int i=1;i<=n;i++)
        if(i!=x)ans=max(ans,dis[i][0]+dis[i][1]);
    printf("%d",ans);
    return 0;
}

 

posted @ 2019-10-15 21:11  fbz  阅读(231)  评论(0编辑  收藏  举报