Silver Cow Party (邻接表)

题意:一群奶牛开party,在X奶牛家开,所有奶牛都要去,找出每头奶牛到X和从X回家的最短路径和,输出路程最长的奶牛走的路,图是单向图;

回家的路好求,单源最短路,Dijkstra算法就可以了,而每头奶牛daoX的最短路不好求,但逆向思考一下,把图改成逆向图,还是X到其他点的单源最短路;

之前一直用邻接矩阵存图,刚学会用邻接表(也有叫链式前向星的,实在没明白两者有啥区别)存图,写一下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#define INF 0x3f3f3f3f
#define MAX1 100005
#define MAX2 1005
using namespace std;
int head[MAX2], rehead[MAX2]; //head X->others; rehead others->X;(边的起点,head[1]=2,以1为起点的边是第二条边)
int N, M, X;
int dis[MAX2], redis[MAX2];   //same with up;
int cnt, recnt;               //所存边的条数;
bool vis[MAX2];               //标记已用边;
struct Edge{                  //结构体存边;
    int v;                    //边的重点;
    int w;                    //边的权;
    int next;                 //同起点的下一条边;
}edge[MAX1], reedge[MAX1];    //
void add_edge(int u, int v, int w){//向edge中存边;
    edge[cnt].v=v;                 //终点;
    edge[cnt].w=w;                 //权重;
    edge[cnt].next=head[u];        //下一条边的起点;
    head[u]=cnt++;                 //以u为起点的边是第几条;
}
void add_reedge(int u, int v, int w){//same with up;
    reedge[recnt].v=v;
    reedge[recnt].w=w;
    reedge[recnt].next=rehead[u];
    rehead[u]=recnt++;
}
void Dijkstra(int s){
    memset(dis,INF,sizeof(dis));//点s到其他点的距离初始化为INF;
    memset(vis,false,sizeof(vis));//所有点均为标记,初始化为false;
    int i, j, k;
    dis[s]=0;                      //s->s距离为零;
    for(i=head[s]; i!=-1; i=edge[i].next){//以s为起点的边;
        j=edge[i].v;
        dis[j]=edge[i].w;;
    }
    for(i=1; i<=N; i++){           //借助每个点松弛一遍;
        int _min=INF;
        for(j=1; j<=N; j++){
        if(!vis[j] && dis[j]<_min){//找到距离s点最近的点;
            _min=dis[j];
            k=j;
        }
        }
        vis[k]=true;              //已经用过的点标记一下,避免重复使用;
        int z;                    //k点是需要借助的松弛点;
        for(z=head[k]; z!=-1; z=edge[z].next){//借助以每个以k为起点的边松弛一下,直到以k为起点的边用完,即next指向-1;
            int to=edge[z].v;
            if(dis[to]>dis[k]+edge[z].w){//if s直接到to的距离大于通过k松弛的距离,就改变dis[to]的值;
                dis[to]=dis[k]+edge[z].w;
            }
        }
    }
}
void reDijkstra(int s){            //逆向存图X到其他点最短路;
    memset(redis,INF,sizeof(redis));
    memset(vis,false,sizeof(vis));
    int i, j, k;
    redis[s]=0;
    for(i=rehead[s]; i!=-1; i=reedge[i].next){
        j=reedge[i].v;
        redis[j]=reedge[i].w;;
    }
    for(i=1; i<=N; i++){
        int _min=INF;

        for(j=1; j<=N; j++){
        if(!vis[j] && redis[j]<_min){
            _min=redis[j];
            k=j;
        }
        }
        vis[k]=true;
        int z;
        for(z=rehead[k]; z!=-1; z=reedge[z].next){
            int to=reedge[z].v;
            if(redis[to]>redis[k]+reedge[z].w){
                redis[to]=redis[k]+reedge[z].w;
            }
        }
    }
}
int main(){
    cnt=recnt=0;
    scanf("%d%d%d",&N,&M,&X);
    memset(head,-1,sizeof(head));
    memset(rehead, -1, sizeof(rehead));
    while(M--){
        int u, v, w;
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u, v, w);     //正向存图;
        add_reedge(v, u, w);   //逆向存图;
    }
    Dijkstra(X);
    reDijkstra(X);
    int _max=-1;
    for(int i=1; i<=N; i++){
        if(_max<dis[i]+redis[i])
            _max=dis[i]+redis[i];
    }
    printf("%d\n",_max);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值