[Usaco2007 Feb]Cow Party

题目描述

农场有N(1≤N≤1000)个牛棚,每个牛棚都有1只奶牛要参加在X牛棚举行的奶牛派对.共有M(1≤M≤100000)条单向路连接着牛棚,第i条踣需要Ti的时间来通过.牛们都很懒,所以不管是前去X牛棚参加派对还是返回住所,她们都采用了用时最少的路线.那么,用时最多的奶牛需要多少时间来回呢?

输入格式

第1行:三个用空格隔开的整数.

第2行到第M+1行,每行三个用空格隔开的整数:Ai, Bi,以及Ti.表示一条道路的起点,终点和需要花费的时间.

输出格式

唯一一行:一个整数: 所有参加聚会的奶牛中,需要花费总时间的最大值.


回去的最少时间好算,就是单源多汇最短路,dijkstra跑一遍就可以了。但是过来的最少时间呢?

问题变成了多源最短路。但不要急着敲Floyd,可以注意到虽然是多源,但是是单汇。如果是从汇点往源点跑的话就可以用dijkstra了。所以在原图的基础上建个反图,过来的时候跑反图,回去的时候跑正图,时间复杂度为O((N+M)*N),加堆优化就是O((N+M)logN)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define maxn 1001
#define maxm 100001
using namespace std;
 
struct graph{
    struct edge{
        int to,dis,next;
        edge(){}
        edge(const int &_to,const int &_dis,const int &_next){
            to=_to,dis=_dis,next=_next;
        }
    }e[maxm];
    int head[maxn],k;
    inline void init(){ memset(head,-1,sizeof head); }
    inline void add(const int &u,const int &v,const int &w){
        e[k]=edge(v,w,head[u]),head[u]=k++;
    }
}a,b;
 
int dis[maxn],ans[maxn];
bool vis[maxn];
int n,m,s;
priority_queue< pair<int,int>,vector< pair<int,int> >,greater< pair<int,int> > > q;
 
inline int read(){
    register int x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
 
inline void dijkstra(const graph &g){
    memset(dis,0x3f,sizeof dis),memset(vis,false,sizeof vis);
    q.push(make_pair(0,s)),dis[s]=0;
    while(q.size()){
        int u=q.top().second; q.pop();
        if(vis[u]) continue; vis[u]=true;
        for(register int i=g.head[u];~i;i=g.e[i].next){
            int v=g.e[i].to;
            if(dis[v]>dis[u]+g.e[i].dis){
                dis[v]=dis[u]+g.e[i].dis;
                q.push(make_pair(dis[v],v));
            }
        }
    }
}
 
int main(){
    a.init(),b.init();
    n=read(),m=read(),s=read();
    for(register int i=1;i<=m;i++){
        int u=read(),v=read(),w=read();
        a.add(u,v,w),b.add(v,u,w);
    }
    dijkstra(a);
    for(register int i=1;i<=n;i++) ans[i]+=dis[i];
    dijkstra(b);
    for(register int i=1;i<=n;i++) ans[i]+=dis[i];
 
    int mmax=0;
    for(register int i=1;i<=n;i++) mmax=max(mmax,ans[i]);
    printf("%d\n",mmax);
    return 0;
}
posted @ 2019-05-14 21:14  修电缆的建筑工  阅读(235)  评论(0编辑  收藏  举报